python解決project euler題目的樂趣

 寒假期間學習了python,現在基本上就能上手使用它來解決project euler裏面的題目了,用python真的是沒得說的,一個字“贊”。在C++中需要用一大堆代碼實現的算法,在python中,只需要那麼短短几行。而且還有驚豔的運行速度。借用《可愛的python》裏面的一句話:“人生苦短,我用python”。

 

【project euler 055】

求經過一系列規則不能得到迴文數的數的個數。題目在此:

If we take 47, reverse and add, 47 + 74 = 121, which is palindromic.

Not all numbers produce palindromes so quickly. For example,

349 + 943 = 1292,
1292 + 2921 = 4213
4213 + 3124 = 7337

That is, 349 took three iterations to arrive at a palindrome.

Although no one has proved it yet, it is thought that some numbers, like 196, never produce a palindrome. A number that never forms a palindrome through the reverse and add process is called a Lychrel number. Due to the theoretical nature of these numbers, and for the purpose of this problem, we shall assume that a number is Lychrel until proven otherwise. In addition you are given that for every number below ten-thousand, it will either (i) become a palindrome in less than fifty iterations, or, (ii) no one, with all the computing power that exists, has managed so far to map it to a palindrome. In fact, 10677 is the first number to be shown to require over fifty iterations before producing a palindrome: 4668731596684224866951378664 (53 iterations, 28-digits).

Surprisingly, there are palindromic numbers that are themselves Lychrel numbers; the first example is 4994.

How many Lychrel numbers are there below ten-thousand?

NOTE: Wording was modified slightly on 24 April 2007 to emphasise the theoretical nature of Lychrel numbers.

 

思路:從1到10000進行逐個掃描,對於每個數進行判斷,是否經過上述規則都不能產生迴文數。在python中,有很方便的做法判斷一個數是否是迴文數。只需比較對稱的列表位置是否相同 arr[i] == arr[lenth-1-i], i從0開始。當然做完之後發現有牛人用幾行代碼就把一切搞定了。不信請看:

 


def Lycheck(n):
   for i in range(0,50):
       n = n+int(str(n)[::-1])
       if str(n)==str(n)[::-1]: return False
   return True
len([n for n in range(10000) if Lycheck(n)])

 

python給我的一個印象就是列表操作很方便,類型轉換超級自由,而且對於大數的運算非常快。這道題目用python解只用了1s。amazing! 另外一個很特別的是,python支持函數式編程,lambda算子可以創建函數對象,傳入某個程式裏面,非常了得。本人在DES的程序中,也看到了類似lambda(x,y: x^y)的函數,非常地神奇,能夠對map裏面的元素都執行這個操作。

 

【project euler 056】

A googol (10100) is a massive number: one followed by one-hundred zeros; 100100 is almost unimaginably large: one followed by two-hundred zeros. Despite their size, the sum of the digits in each number is only 1.

Considering natural numbers of the form, ab, where a, b < 100, what is the maximum digital sum?

思路: 很明顯,這個位的和要大,顯然要夠長。既要夠長,每位數字的數字也要夠長。我腦海裏面立馬蹦出了99的99次方這樣的數字。但是不能想當然,我還是從91開始,計算到100,鐵定能夠找到那個各位和最大的數。程序如下:


# project euler 56
# !/usr/bin/python
# -*- coding: utf-8 -*-
import sys


def power_digit_sum():
	max_digits_sum = 0
	for i in range(91,100):
		for j in range(91,100):
			power_num = pow(i,j)
			print power_num
			digits_sum = sum_digits(power_num)
			print digits_sum
			if digits_sum > max_digits_sum:
				max_digits_sum = digits_sum
	print max_digits_sum
			
			
def sum_digits( power_num):
	digits_sum = 0
	while power_num != 0 :
		rear_num = power_num % 10
		power_num = power_num / 10
		digits_sum += rear_num
	return digits_sum
	#return sum(map(int, power_num))


power_digit_sum()

 

運行就能夠找到答案了。

【project euler 057】

 

It is possible to show that the square root of two can be expressed as an infinite continued fraction.

√ 2 = 1 + 1/(2 + 1/(2 + 1/(2 + ... ))) = 1.414213...

By expanding this for the first four iterations, we get:

1 + 1/2 = 3/2 = 1.5
1 + 1/(2 + 1/2) = 7/5 = 1.4
1 + 1/(2 + 1/(2 + 1/2)) = 17/12 = 1.41666...
1 + 1/(2 + 1/(2 + 1/(2 + 1/2))) = 41/29 = 1.41379...

The next three expansions are 99/70, 239/169, and 577/408, but the eighth expansion, 1393/985, is the first example where the number of digits in the numerator exceeds the number of digits in the denominator.

In the first one-thousand expansions, how many fractions contain a numerator with more digits than denominator?

思路:找規律,發現只要用幾個變量就可以完全表示好這個式子的模式,從下往上看,有相當一部分x=(1/(2+1/2)),是由上一步產生的,而每步都是1+1/(2+x)組成的,而x的產生可以是遞歸的。另外第一次i=0的時候,比較特殊,是1+x的模式。

總結規律如下:

 

 


# 計算展開式 e
# count 第幾次展開, 採用遞歸法則
def cal_expansion(count,a,b):
   c = 1   
   d = 1    
   e = 2   # (2 + 1/2) 加號前的2
   if count == 0:  # first time is special
     c = b + a
     d = b
     return a,b,c,d   # 遞歸最底層
   elif count > 0:  # the second time is special
     a = (b*e) + a
     a,b = swap(a,b)
     #print count,a,b
     count = 0            ​# 因爲採用了自上而下,故而不這裏的遞歸需要有所修改,直接奔第0次
     return  cal_expansion(count,a,b) #遞歸調用
 
# swap function
def swap(a, b):
    b,a = a,b
    return a,b


TIMES = 1000
# every time 
a,b,c,d = 1,2,1,1
count = 0
strc,strd ="",""
for i in range(0,TIMES):
    print i,"(",a,"/",b,")",c,d
    a,b,c,d = cal_expansion(i,a,b)   # 重複傳遞的a/b部分,如1/2, 2/5,5/12等,以及整個式子的結果c/d,如3/2
    strc,strd = str(c),str(b)
    if len(strc) > len(strd):  #位數比較
        count +=1
print count

 

程序採用了遞歸,但是考慮到從上往下計算將會節省很多時間,故而用迭代進行計算。原以爲迭代和遞歸是矛盾的,不能同時使用的,但是我先計算出的成果,從是能夠運用到下一步的計算當中。這令我非常有成就感。下面是運行的例子:

點擊查看原圖

鏈接 projectEuler

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章