from simple_profile import timed_call def product(iterable): return reduce(lambda x, y: x * y, iterable, 1) ## naive solution def solution1(): return max(product(digits[i:i + 5]) for i in range(len(digits) - 5 + 1)) ## a little better - get rid of errors def solution2(): max_product = 0 i = 0 while i < len(digits) - 5: if digits[i + 4] == 0: i += 9 continue p = product(digits[i:i + 5]) if p > max_product: max_product = p i += 1 return max_product ## tests if __name__ == '__main__': print timed_call(solution1) ## 0.00236 secs print timed_call(solution2) ## 0.00100 secs
] if N - sum(solution) >= solution[1] else [] else: return [ solution + [n] for n in range(solution[0], (N - solution[0]) / 2 + 1) ] frontier = [[n] for n in range(1, N - 1)] ## partial/complete solutions while frontier: solution = frontier.pop() if is_complete(solution): yield solution else: frontier += next(solution) ## simplication of backtracking sine the number of parts in solution is fixed def solution2(): N = 1000 for a in range(1, int(ceil(N / 3)) + 1): for b in range(a, int(ceil((N - a) / 2)) + 1): c = N - a - b if a**2 + b**2 == c**2: yield (a, b, c) ## tests if __name__ == '__main__': print timed_call(lambda: product(next(solution1()))) ## 0.05 print timed_call(lambda: product(next(solution2()))) ##
if prime_powers else 1) def solution1(): N = 500 def triangles(): t, i = 1, 1 while True: yield t i += 1 t += i return next(t for t in triangles() if num_factors(t) > N) ## tests if __name__ == '__main__': ## test prime_factors assert [(n, prime_factors(n)) for n in range(1, 21)] == [ (1, {}), (2, {2: 1}), (3, {3: 1}), (4, {2: 2}), (5, {5: 1}), (6, {2: 1, 3: 1}), (7, {7: 1}), (8, {2: 3}), (9, {3: 2}), (10, {2: 1, 5: 1}), (11, {11: 1}), (12, {2: 2, 3: 1}), (13, {13: 1}), (14, {2: 1, 7: 1}), (15, {3: 1, 5: 1}), (16, {2: 4}), (17, {17: 1}), (18, {2: 1, 3: 2}), (19, {19: 1}), (20, {2: 2, 5: 1})] ## test num_factors assert [(n, num_factors(n)) for n in (1, 3, 6, 10, 15, 21, 28)] == [(1, 1), (3, 2), (6, 4), (10, 4), (15, 4), (21, 4), (28, 6)] ## test solution1 t, r = timed_call(solution1) assert r == 76576500 assert t < 7 print 'all tests pass'
2: 1, 7: 1 }), (15, { 3: 1, 5: 1 }), (16, { 2: 4 }), (17, { 17: 1 }), (18, { 2: 1, 3: 2 }), (19, { 19: 1 }), (20, { 2: 2, 5: 1 })] ## test num_factors assert [(n, num_factors(n)) for n in (1, 3, 6, 10, 15, 21, 28)] == [(1, 1), (3, 2), (6, 4), (10, 4), (15, 4), (21, 4), (28, 6)] ## test solution1 t, r = timed_call(solution1) assert r == 76576500 assert t < 7 print 'all tests pass'
Find the sum of all the primes below two million. """ ## backenvlope 2x10**6 for O(n2) from simple_profile import timed_call def prime_sieve(hi): primes = [True for _ in range(hi)] primes[0] = primes[1] = False current = 2 s = 0 while current < hi: s += current i = 2 while current * i < hi: primes[current * i] = False i += 1 current += 1 while current < hi and not primes[current]: current += 1 return sum(p for p in range(hi) if primes[p]) ## tests if __name__ == '__main__': N = 2000000 # test prime_sieve print timed_call(prime_sieve, N) ## 2.08
## n has no factors in between 2 to i ## n is always >= i (for i * i <= n), so it is bigger than all other prime factors ## n is a factor of N ## => there is prime factor larger than n ################## Why the algorithm is correct ############## ## Because of the loop invariance ############################################################## def largest_prime_factor(N): i, n = 2, N while i * i <= n: while n % i == 0 and n > i: n = n / i #largest_prime_factor.count += 1 i += 1 return n ## Solution 2 ## find factors in O(sqrt(N)) and do the prime test ## find the max prime factor # tests if __name__ == '__main__': ## test the largest prime number largest_prime_factor.count = 0 #assert largest_prime_factor(N) == 6857 #print largest_prime_factor.count from simple_profile import timed_call #N = 688543 print timed_call(largest_prime_factor, N)
while nums: factor = min(nums) factors.append(factor) nums = filter(lambda x: x > 1, map(lambda x: x / factor if x % factor == 0 else x, nums)) return factors def solution1(N): return reduce(lambda x, y: x * y, factor_union(N), 1) def solution2(N): def gcd(a, b): return b and gcd(b, a % b) or a def lcm(a, b): return a * b / gcd(a, b) n = 1 for i in range(1, N + 1): n = lcm(n, i) return n if __name__ == "__main__": ## test sieve for primes ## print sieve(20) t1, r1 = timed_call(solution1, 20) t2, r2 = timed_call(solution2, 20) print t1 < t2
def next(solution): L = len(solution) if L == 3: return [] elif L == 2: return [solution + [N-sum(solution)]] if N-sum(solution) >= solution[1] else [] else: return [solution + [n] for n in range(solution[0], (N-solution[0])/2 + 1)] frontier = [[n] for n in range(1, N-1)] ## partial/complete solutions while frontier: solution = frontier.pop() if is_complete(solution): yield solution else: frontier += next(solution) ## simplication of backtracking sine the number of parts in solution is fixed def solution2(): N = 1000 for a in range(1, int(ceil(N/3))+1): for b in range(a, int(ceil((N-a)/2))+1): c = N - a - b if a**2 + b**2 == c**2: yield (a, b, c) ## tests if __name__ == '__main__': print timed_call(lambda: product(next(solution1()))) ## 0.05 print timed_call(lambda: product(next(solution2()))) ##
## use the fact that nums starts from 1 def factor_union(N): factors = [] nums = range(2, N+1) while nums: factor = min(nums) factors.append(factor) nums = filter(lambda x: x > 1, map(lambda x: x/factor if x%factor == 0 else x, nums)) return factors def solution1(N): return reduce(lambda x, y: x*y, factor_union(N), 1) def solution2(N): def gcd(a, b): return b and gcd(b, a % b) or a def lcm(a, b): return a * b / gcd(a, b) n = 1 for i in range(1, N+1): n = lcm(n, i) return n if __name__ == '__main__': ## test sieve for primes ## print sieve(20) t1, r1 = timed_call(solution1, 20) t2, r2 = timed_call(solution2, 20) print t1 < t2
The square of the sum of the first ten natural numbers is, (1 + 2 + ... + 10)**2 = 552 = 3025 Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 - 385 = 2640. Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum. """ from itertools import combinations from simple_profile import timed_call N = 100 ## solution 1 def solution1(): return sum([ 2 * n1 * n2 for (n1, n2) in combinations(range(1, N+1), 2) ]) ## solution 2 def solution2(): ns = xrange(1, N+1) s = sum(ns) return s * s - sum(n * n for n in ns) print timed_call(solution1) print timed_call(solution2)
def prime_generator(): primes = [2] def is_prime(n): for p in primes: if p * p > n: return True if n % p == 0: return False while True: yield primes[-1] n = primes[-1] + 1 while not is_prime(n): n += 1 primes.append(n) def solution1(): N = 10001 primes = prime_generator() for i in range(1, N): next(primes) return next(primes) ## tests if __name__ == '__main__': print timed_call(solution1) # 0.18 s
from simple_profile import timed_call def product(iterable): return reduce(lambda x,y: x*y, iterable, 1) ## naive solution def solution1(): return max( product(digits[i:i+5]) for i in range(len(digits) - 5 + 1) ) ## a little better - get rid of errors def solution2(): max_product = 0 i = 0 while i < len(digits) - 5: if digits[i+4] == 0: i += 9 continue p= product(digits[i:i+5]) if p > max_product: max_product = p i += 1 return max_product ## tests if __name__ == '__main__': print timed_call(solution1) ## 0.00236 secs print timed_call(solution2) ## 0.00100 secs
## the performance depends on how sparse the primes ## are within the range def prime_generator(): primes = [2] def is_prime(n): for p in primes: if p * p > n: return True if n % p == 0: return False while True: yield primes[-1] n = primes[-1] + 1 while not is_prime(n): n += 1 primes.append(n) def solution1(): N = 10001 primes = prime_generator() for i in range(1, N): next(primes) return next(primes) ## tests if __name__ == '__main__': print timed_call(solution1) # 0.18 s