今天來看一道有點意思的題目,有點意思的意思呢,不是說難,而是題目一想好像很難,但是如果找對了解決的思路,就能迎刃而解了。
問題是這樣的:
假如這裡有 n 個台階,你可以選擇每次完成乙個台階 或者 兩個台階,試問走完這 n 個台階有多少種走法呢?在往下看答案之前,你可以嘗試自己思考如果是你自己來完成這道題目,會有什麼思路?舉個例子,如果有 7 個台階,你可以選擇 2 - 2 - 2 - 1 走完,也可以選擇 2 - 1 - 1 - 1 - 2 走完。
接下來,我就分享一下這個題目的解法。
你可能不會想到這個題目居然可以用遞迴來解決吧?真的是思路清晰,簡單又粗暴。
首先,你跨出的每個第一步,都只有兩種選擇,要麼跨出乙個台階,要麼跨出兩個台階。而每個下一步又是乙個全新的開始,又面臨著兩種選擇。你看,有點遞迴的味道了吧?每個過程都是重複的過程。
寫遞迴函式,有兩個最重要的點:
用 python 寫一下:
def calc_step_recursion(num):
if num == 1:
return 1
if num == 2:
return 2
return calc_step_recursion(num - 1) + calc_step_recursion(num - 2)
計算一下結果有多驚人
calc_step_recursion(10)
# 89
calc_step_recursion(20)
# 10946
如果今天只有這點內容那就太沒有誠意了。
讓我們嘗試著對這個函式進行深度思考,就會發現這個函式會有一些問題。
第乙個問題
這個遞迴寫得雖然簡潔,但是卻有大量的重複計算。比如:
f(5) = f(4) + f(3)
= f(3) + f(2) + f(3)
= f(2) + f(1) + f(2) + f(2) + f(1)
這裡面,f(2) 就要運算 3 次,f(1) 要運算 2 次。
當我們的 n 為乙個比較大的數時,這個運算過程會浪費很多的時間。
正好之前在看 《流暢的python》 這本書的時候,學習到了乙個非常好用的內建裝飾器(lru_cache)。它可以將這些函式的執行結果儲存下來(其實就是快取),避免傳入重複引數造成重複計算。
import functools
@functools.lru_cache()
def calc_step_recursion(num):
if num == 1:
return 1
if num == 2:
return 2
return calc_step_recursion(num - 1) +
calc_step_recursion(num - 2)
來看看加上這個裝飾器後,效能到底提公升了多少,這裡用時間來衡量。
# 不加
calc_step_recursion(40)
# time:25.780471086502075 秒
# 加calc_step_recursion(40)
# time:0.0001678466796875 秒
第二個問題
使用遞迴的時候,我們都知道遞迴會出現堆疊溢位的風險。
為了避免這個問題,通常我們會將這個遞迴實現轉換成迴圈迭代。
def calc_step_loop(num):
step1 = 1
step2 = 2
for step in range(2, num):
total = step1 + step2
step2, step1 = total, step2
return total
使用迭代迴圈的方式,不僅不會有重複計算的問題,而且又避免出現堆疊溢位的風險。可謂是一舉兩得。
同樣地,也來看一下,它的執行時長,比使用遞迴的方法可好多了。
calc_step_loop(40)
# time:0.0000348091125488 秒
在寫**的時候,個人建議在實現基本的功能需求後,應當放些精力在**的優化上,盡自己最大的努力,提高**的健壯性及其效能等。這樣才能變成乙個有靈魂的程式設計師,而不是只會 crud 的碼農。 程式設計師買房子,,,一道簡單題
題目 總時間限制 1000ms 記憶體限制 65536kb 描述 某程式設計師開始工作,年薪n萬,他希望在中關村公館買一套60平公尺的房子,現在 是200萬,假設房子 以每年百分之k增長,並且該程式設計師未來年薪不變,且不吃不喝,不用交稅,每年所得n萬全都積攢起來,問第幾年能夠買下這套房子?第一年年...
一道演算法題,引發的思考
引言 有人問我這樣乙個問題,希望寫出 實現 有p0,p1兩點座標,組成乙個線段,求此線段與x點的的距離 我並不知道,如何完全的實現此功能,因為求點與線的公式,我記得是高中知識,但是我已經忘得差不多了,只是知道勾股定理算兩點間距離,直線方程有個斜率,如果給我時間去細想的話,應該可以理出頭緒,得到個寫此...
一道程式設計師面試的經典悖論問題
如果叫你從下面兩種遊戲中選擇一種,你選擇哪一種?為什麼?a.寫下一句話。如果這句話為真,你將獲得10美元 如果這句話為假,你獲得的金錢將少於10美元或多於10美元 但不能恰好為10美元 b.寫下一句話。不管這句話的真假,你都會得到多於10美元的錢。答案 選擇第一種遊戲,並寫下 我既不會得到10美元,...