程式設計師走樓梯都會思考的一道題

2021-09-04 09:51:12 字數 2326 閱讀 1001

今天來看一道有點意思的題目,有點意思的意思呢,不是說難,而是題目一想好像很難,但是如果找對了解決的思路,就能迎刃而解了。

問題是這樣的:

假如這裡有 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美元,...