Project Euler上的部分算法题 解法+笔记

很多算法的问题都涉及质数,所以有必要先讨论一下关于质数的那些事

有以下事实

①.除了2以外所有的质数都是奇数

②.任何正整数N只能有一个大于根号N的质因子

③.任何小于正整数N的合数都有小于根号N的因子


Eratosthenes筛选法是用来寻找质数的算法,原理是这样的:比如求小于1000的质数,2是质数,去掉所有2的倍数,继,3没有被去掉,所以3是质数,去掉3的倍数,直到根号1000。这样剩下来的数就都是质数了。


用python实现Sieve算法求解10000以内的质数,只用了0.1秒

代码如下

#!/usr/bin/env python
import math

def Sieve(n):
	''' (int) -> list of int
	Return a list of all the prime numbers less than n.
	At least n should be more than 6.
	'''
	marked = [0] * (n + 1)
	value = 3
	i = value
	primes = [2]
	while value < math.sqrt(n):
		primes.append(value)
		i += value
		while i < n:
			marked[i] = 1
			i += value
		value += 2

	for i in range(3, n, 2):
		if marked[i] == 0:
			primes.append(i)
	return primes

下面是正文,一共十几个题目。

P1:Multiples of 3 and 5

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.

也就是求1000以内所有是3和5的倍数的数的和。

我自己写的方法如下:

sum_num = 0
for i in range(1, 1000):
    if i % 3 == 0 or i % 5 == 0:
        sum_num += i

在论坛里又看了其他人的做法,自己的做法果然是最直接也是最笨的。例如加拿大的rayfil的方法:

start:
      xor   edx,edx           ;sum
 
      mov   eax,3
   .while eax < 1000
      add   edx,eax
      add   eax,3
   .endw
 
      mov   eax,5
   .while eax < 1000
      add   edx,eax
      add   eax,15
   .endw
 
      mov   eax,10
   .while eax < 1000
      add   edx,eax
      add   eax,15
   .endw

还有Rudy的方法:Exactly! This was another one that I solved without code, also. First of all, stop thinking on the number 1000 and turn your attention to the number 990 instead. If you solve the problem for 990 you just have to add 993, 995, 996 & 999 to it for the final answer. This sum is (a)=3983

Count all the #s divisible by 3: From 3... to 990 there are 330 terms. The sum is 330(990+3)/2 (b)=163845

Count all the #s divisible by 5: From 5... to 990 there are 198 terms. The sum is 198(990+5)/2 (c)=98505 Now, the GCD (greatest common divisor) of 3 & 5 is 1 so the LCM (least common multiple) should be 3x5 15.

This means every number that divides by 15 was counted twice and it should be done only once. Because of this, you have an extra set of numbers started with 15 all the way to 990 that has to be removed from (b)&(c). Then, from 15... to 990 there are 66 terms and the sum is 66(990+15)/2 (d)=33165 The answer for the problem is: (a)+(b)+(c)-(d) = 233168 Simple but very fun problem.

这家伙不用代码就搞定了问题,主要也就是找到了990这个数字,然后用等差数列求和的方式分别求出a, b, c, d。


P2:Even Fibonacci numbers

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

意思是求小于4000000的Fibonacci数中所有偶数的和。我的直接解法:

def fib(i):
    if i == 1 or i == 2:
        return 1
    else:
        return fib(i-2) + fib(i-1)
 
def f1():
    i = 1
    sum_num = 0
    while True:
        num = fib(i)
        if num % 2 == 0 and num <= 4000000:
            sum_num += num
        if num > 4000000:
            break
        i += 1
    print sum_num

唉,目不忍视啊,我的计算机算了接近7秒。效率是如此的低。不过因为这样找到差距才能进步。

提供的答案的解法:

def f2():
    s = 0
    a = 1
    b = 1
    while b < 4000000:
        if b % 2 == 0:
            s += b
        h = a + b
        a = b
        b = h
    print s

只需要0.021秒。

另python中可以使用cProfile模块测试算法性能

>>> import cProfile

>>> cProfile.run("f()")


P3: Largest prime factor

The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?

意思是求600851475143这个大数的最大质因子。

Still, 先来我的蜗牛算法:

import math
 
def is_prime(n):
    '''
    Return True if n is a prime number.
    '''
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i != 0:
            continue
        else:
            return False
 
    return True
     
def largest_prime_factor(n):
    i = 2
    while i < n:
        if n % i == 0:
            factor = n / i
            if is_prime(factor):
                return factor
        i += 1

30+秒才出结果。

给出的答案的方法:

def f(n):
    factor = 2
    lastFactor = 1
    while n > 1:
        if n % factor == 0:
            lastFactor = factor
            n = n / factor
            while n % factor == 0:
                n = n / factor
        factor += 1
    print n
    return lastFactor

答案的这种方法在寻找最大质因数的过程中,让所求数是质数的条件自动满足。


P4: Largest palindrome product

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 &times; 99.

Find the largest palindrome made from the product of two 3-digit numbers.

求两个三位数相乘得到的最大的回文数。

我的Brutal force解法,求出所有的回文数,然后找出最大的:

def is_palindrome(s):
    i = 0
    j = len(s) - 1
 
    while i < j and s[i] == s[j]:
        i += 1
        j -= 1
 
    return j <= i
 
def f1():
    palindrome_list = []
    for i in range(1000, 100, -1):
        for j in range(1000, 100, -1):
            if is_palindrome(str(i*j)):
                palindrome_list.append(i*j)
    palindrome_list.sort()
    return palindrome_list[-1]

答案的解法:

def f2():
    largestPalindrome = 0
    a = 100
    while a <= 999:
        b = a
        while b <= 999:
            if is_palindrome(str(a*b)) and a*b > largestPalindrome:
                largestPalindrome = a*b
            b = b + 1
        a = a + 1
    return largestPalindrome

进一步优化:

def f3():
    largestPalindrome = 0
    a = 999
    while a >= 100:
        b = 999
        while b >= a:
            if a*b <= largestPalindrome:
                break
            if is_palindrome(str(a*b)):
                largestPalindrome = a*b
            b -= 1
        a -= 1
    return largestPalindrome



P5: Sum square difference

The sum of the squares of the first ten natural numbers is,

2 + 2 2 + ... + 10 2 = 385

The square of the sum of the first ten natural numbers is,

(1 + 2 + ... + 10) 2 = 55 2 = 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.

解:

numbers = []
for i in range(1, 101):
    numbers.append(i)
 
 
print sum(numbers) ** 2 - sum([n ** 2 for n in numbers])


P6: Smallest multiple

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

bitRAKE的解法:

This does not require programming at all. Compute the prime factorization of each number from 1 to 20, and multiply the greatest power of each prime together: 

20 = 2^2 * 5

19 = 19

18 = 2 * 3^2

17 = 17

16 = 2^4

15 = 3 * 5

14 = 2 * 7

13 = 13

11 = 11

All others are included in the previous numbers. ANSWER: 2^4 * 3^2 * 5 * 7 * 11 * 13 * 17 * 19 = 232 792 560

我也考虑到根本不需要写代码的,但数学功底不行,算了半天。想分解成因子的形式却总是算错。原来关键是找出它们的质数因子。


P7: 10001st prime

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.

What is the 10 001st prime number?

Brutal force:

#!/usr/bin/env python
base = [2, 3, 5, 7, 11, 13]
new_prime = base[-1] + 1
while len(base) < 10001:
    for p in base:
        if new_prime % p == 0:
            break
        if p == base[-1]:
            base.append(new_prime)
    new_prime += 1
 
print base[-1]


P8: Largest product in a series

Find the greatest product of five consecutive digits in the 1000-digit number.

73167176531330624919225119674426574742355349194934

96983520312774506326239578318016984801869478851843

85861560789112949495459501737958331952853208805511

12540698747158523863050715693290963295227443043557

66896648950445244523161731856403098711121722383113

62229893423380308135336276614282806444486645238749

30358907296290491560440772390713810515859307960866

70172427121883998797908792274921901699720888093776

65727333001053367881220235421809751254540594752243

52584907711670556013604839586446706324415722155397

53697817977846174064955149290862569321978468622482

83972241375657056057490261407972968652414535100474

82166370484403199890008895243450658541227588666881

16427171479924442928230863465674813919123162824586

17866458359124566529476545682848912883142607690042

24219022671055626321111109370544217506941658960408

07198403850962455444362981230987879927244284909188

84580156166097919133875499200524063689912560717606

05886116467109405077541002256983155200055935729725

71636269561882670428252483600823257530420752963450

一个一个找呗:

p7data = open('p7data.txt', 'r')
data = p7data.read()
data_tmp = list(data.split('\n'))
data_list = []
for s in data_tmp:
    for i in list(s):
        data_list.append(int(i))
i = 0
j = 5
short_list = data_list[i:j]
larggest_num = 0
while j < len(data_list):
    short_list = data_list[i:j]
    tmp_num = reduce(lambda x, y: x*y, short_list)
    if larggest_num < tmp_num:
        larggest_num = tmp_num
    i += 1
    j += 1
 
print larggest_num


P9: Special Pythagorean triplet

A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,

2 + b 2 = c 2

For example, 32 + 42 = 9 + 16 = 25 = 52.

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

我的解法,参照了网上的写法,脑袋卡壳了,老是在想怎么解方程用什么巧妙的方法来解决

现在发现直接想着怎么解决这个问题就行了,make it right before you make it faster, lol.

#!/usr/bin/env python
 
sum = 1000
for a in range(sum // 3):
    for b in range(sum // 2):
        c = sum - a - b
        if c > 0 and a ** 2 + b ** 2 == c ** 2:
            print a*b*c

Pier的做法让我震惊了

Without programming: 

a= 2mn; b= m^2 -n^2; c= m^2 + n^2;

a + b + c = 1000;

2mn + (m^2 -n^2) + (m^2 + n^2) = 1000;

2mn + 2m^2 = 1000;

2m(m+n) = 1000;

m(m+n) = 500;

m>n;

m= 20; n= 5;

a= 200; b= 375; c= 425;


P10: Summation of primes

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.

#!/usr/bin/env python
# import math
# ---------------------------------------------------------------------------------------------------
# my solution - normal and slow
def is_prime(n):
    '''
    Return True if n is a prime number.
    '''
    for i in range(2, int(math.sqrt(n)) + 1):
        if n % i != 0:
            continue
        else:
            return False
 
    return True
 
result = 0
n = 2000000 - 1
while n > 1:
    if is_prime(n):
        result += n
    n -= 2
 
print result + 2
 
# ----------------------------------------------------------------------------
# python sieve - by lassevk
marked = [0] * 2000000
value = 3
s = 2
while value < 2000000:
    if marked[value] == 0:
        s += value
        i = value
        while i < 2000000:
            marked[i] = 1
            i += value
    value += 2
print s


转载于:https://my.oschina.net/seandor/blog/153189

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值