題目:有樓梯n階,從下往上走,每一步只能跨1階或者2階,問總共有多少種不同走法
比如,每次走1級臺階,一共走10步。我們可以簡寫成 1,1,1,1,1,1,1,1,1,1;
再比如,每次走2級臺階,一共走5步。我們可以簡寫成 2,2,2,2,2。
解答:
----------------------------------------step.go---------------------------------------------
package dynamicprograming // 思路:設f(x)爲走到第x階可能的情況,則最後踏上第n階的前一步有兩種情況,n-1 到 n,或者n-2 到 n,也就是f(n)=f(n-1)+f(n-2) // 又有f(1)=1,f(2)=2 (1+1和2兩種情況) // 遞歸方式,時間複雜度 o(2^n) func f0(n int) int { if n < 1 { return 0 } if n == 1 || n == 2 { return n } return f0(n-1) + f0(n-2) } // 由於f0的遞歸方式中,計算f(n-1)時,f(1)...f(n-2)都已經計算過了,再次計算f(n-2)...f(1)時會重複計算,因此把這些值保存起來避免重複 // 備忘錄遞歸 時間複雜度 o(n),空間複雜度o(n) func f1(n int, m map[int]int) (ret int) { if n < 1 { return 0 } if n == 1 || n == 2 { return n } ret, exists := m[n] if !exists { ret = f1(n-1, m) + f1(n-2, m) m[n] = ret } return ret } // f1計算時發現,計算f(n)只要知道f(n-2)和f(n-1)即可,n從1遍歷到n,會計算所有的f(1)到f(n-1), // 因此依次計算f(1)到f(n-1),並由最後兩個值f(n-2),f(n-1)推出f(n)即可 // 動態規劃 時間複雜度 o(n),空間複雜度o(1) func f2(n int) int { if n < 1 { return 0 } if n == 1 || n == 2 { return n } a, b, temp := 1, 2, 0 for i := 3; i < n+1; i++ { temp = a + b a = b b = temp } return temp }
--------------------------------------step_test.go--------------------------------------------------
package dynamicprograming import ( "testing" "fmt" "time" ) var n=30 func TestF0(t *testing.T) { start:=time.Now().UnixNano() defer func() { fmt.Println("遞歸耗時",time.Now().UnixNano()-start) }() fmt.Println(f0(n)) } func TestF1(t *testing.T) { start:=time.Now().UnixNano() defer func() { fmt.Println("備忘錄遞歸耗時",time.Now().UnixNano()-start) }() m:=make(map[int]int,n) fmt.Println(f1(n,m)) } func TestF2(t *testing.T) { start:=time.Now().UnixNano() defer func() { fmt.Println("動態規劃耗時",time.Now().UnixNano()-start) }() fmt.Println(f2(n)) }