4
\$\begingroup\$

Project Euler problem 9 says:

A Pythagorean triplet is a set of three natural numbers, \$a < b < c\,ドル for which, $$a^2 + b^2 = c^2$$ For example, \3ドル^2 + 4^2 = 9 +たす 16 = 25 = 5^2\$.

There exists exactly one Pythagorean triplet for which \$a + b + c = 1000\$.
Find the product \$abc\$.

My code finds the correct solution to the problem. The problem is it takes 47.6 seconds to get it, so I'd like to optimize it, but don't know exactly how to do so further. I've already reduced the range of the for loops.

import time
s=time.time()
a=0
b=0
c=0
for i in range(1,499): #max value for any side of the triangle must be less than the semiperimeter
 for j in range(i,499):
 for k in range(j,499):
 if(i+j+k==1000 and i**2+j**2==k**2):
 a=i
 b=j
 c=k
 break #the solution is unique, so when it finds a solution, it doesnt need to go through any other loops.
print(a*b*c,time.time()-s)
Gareth Rees
50.1k3 gold badges130 silver badges210 bronze badges
asked May 19, 2016 at 10:53
\$\endgroup\$

2 Answers 2

4
\$\begingroup\$
for i in range(1,499): #max value for any side of the triangle must be less than the semiperimeter
 for j in range(i,499):
 for k in range(j,499):
 if(i+j+k==1000 and i**2+j**2==k**2):

There are a couple quick optimizations.

for i in range(1,333):

You can restrict this beyond 499. We know that \$ a < b < c\$ and \$a + b + c = 1000\,ドル so we can say that \3ドル*a < 1000\$ or \$a \leq 333\$.

 for j in range(i,499): #max value for any side of the triangle must be less than the semiperimeter
 k = 1000 - i - j

We don't need to iterate to find k. We can calculate it from i and j since we know that the three sum to 1000.

 if (i**2+j**2==k**2):

So we can just check that it's a Pythagorean triple. The sum will always be correct, as that's how we select k.

Just calculating k instead of iterating to find it should reduce the time to less than a second.

answered May 19, 2016 at 11:36
\$\endgroup\$
0
1
\$\begingroup\$

Another easy optimisation would be to fix the early return. As you said, you should stop the search when you found the result, but by using break, you only break the innermost loop, and the search continues. I suggest moving the search into a function which would return when the result is found. This by itself reduces the run time by almost 50%:

import time
def pythagorean_triplet(limit):
 # value of any side of the triangle must be less than the semiperimeter
 semiperimeter = limit // 2
 for i in range(1, semiperimeter):
 for j in range(i, semiperimeter):
 for k in range(j, semiperimeter):
 if(i+j+k == limit and i**2+j**2 == k**2):
 # the solution is unique, so when it finds a solution, it
 # doesnt need to go through any other loops.
 return i, j, k
s = time.time()
a, b, c = pythagorean_triplet(1000)
print(a*b*c, time.time()-s)

The above snippet also includes some style changes to conform to pep8, and changes the second range argument (semiperimeter) from 499 to 500, since the range function goes up to but not including the stop value.

answered May 20, 2016 at 13:29
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.