青蛙跳臺階One
問題描述
一只青蛙一次可以跳1級臺階,也可以跳2級臺階。求該青蛙跳上一個n級的臺階總共有多少種跳法。
青蛙跳臺階問題是一個經(jīng)典的遞歸問題,也可以使用動態(tài)規(guī)劃來解決。
問題分析
設(shè)f(n)表示青蛙跳上n級臺階的跳法數(shù)。
當(dāng)只有一個臺階時,即n = 1時, 只有1中跳法:一次跳上去。
f(1) = 1
當(dāng)n = 2時,有兩種跳法:
- 可以一次跳一階,2次跳上去。
- 也可以一次跳兩階。
f(2) = 2
當(dāng)n = 3 時,有3種跳法:
- 一次跳一階,一次跳兩階,跳2次。
- 一次跳兩階,一次跳一階,跳2次。
- 一次跳一階,跳3次。
f(3) = 3
當(dāng)n很大時,青蛙在最后一步跳到第n級臺階時,有兩種情況:
- 一種是青蛙在第
n-1
個臺階,跳1個臺階到第n個臺階,那么青蛙跳完前面n-1個臺階,就有f(n-1)
種跳法,這是一個子問題。 - 另一種是青蛙在第
n-2
個臺階,跳2個臺階到第n個臺階,那么青蛙完成前面n-2個臺階,就有f(n-2)
種情況,這又是另外一個子問題。
兩個子問題構(gòu)成了最終問題的解,所以當(dāng)n>=3時,青蛙就有 f(n)=f(n-1)+f(n-2)
種跳法。
上面的分析過程,用數(shù)學(xué)方程表達(dá)如下:
算法實現(xiàn)
遞歸解法
/**
* 遞歸解法
*
* @param n 臺階數(shù) n>=3
* @return
*/
static int frogJumpRecursively(int n) {
if (n == 1) {
return 1;
} else if (n == 2) {
return 2;
} else {
return frogJumpRecursively(n - 1) + frogJumpRecursively(n - 2);
}
}
動態(tài)規(guī)劃解法
/**
* 動態(tài)規(guī)劃解法
*
* @param n 臺階數(shù) n>=3
* @return
*/
static int frogJump(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
//n從3開始,preTwo就代表n為1時的跳法數(shù)
int preTwo = 1;
//n從3開始,preOne就代表n為2時的跳法數(shù)
int prepOne = 2;
//跳上n階所需要的總的跳法
int jumpN = 0;
for (int i = 3; i <= n; i++) {
jumpN = preTwo + prepOne;
preTwo = prepOne;
prepOne = jumpN;
}
return jumpN;
}
動態(tài)規(guī)劃的解法 Copilot 給的寫法感覺更好理解
/**
* 動態(tài)規(guī)劃的解法,Copilot推薦的解法,感覺更好理解
* @param n
* @return
*/
static int jumpFloor(int n) {
if(n <= 0) {
return 0;
}
if(n == 1) {
return 1;
}
if(n == 2) {
return 2;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for(int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
青蛙跳臺階Two
問題描述
一只青蛙一次可以跳上1級臺階,也可以跳上2級,也可以跳上,……也可以跳上n級,那么青蛙跳上一個n級的臺階總共有多少種跳法?
問題分析
關(guān)于本題,存在n級臺階1次就跳上去的跳法。分析如下:
要跳上第n級臺階,可以從第n?1級臺階一次跳上來,也可以可以從第n?2級臺階一次跳上來,也可以可以從第n?3級臺階一次跳上來,…,也可以可以從第1級臺階一次跳上來,也可以從第0級臺階一次跳上來。那么問題就很簡單啦,同樣的,令f(n) 表示跳上第n級臺階有幾種跳法。則有如下遞推公式:
f(n)=f(n?1)+f(n?2)+...+f(1)+f(0)
f(n-1)=f(n?2)+...+f(1)+f(0)
兩式相減得:f(n)-f(n-1)=f(n-1),所以f(n) = 2f(n-1)。
注意當(dāng)n為0和n為1的時候,是不滿足f(n) = 2f(n-1)這個公式的。
f(0)=1:表示一次跳n級臺階的跳法
f(1)=1: 表示一次跳一級臺階(也可以認(rèn)為是和f(0)是等價的,表示一次跳n級臺階的跳法,只不過此時n為1)。
綜上所述:
算法實現(xiàn)
遞歸實現(xiàn)
/**
* 遞歸實現(xiàn)
*
* @param n
* @return
*/
static int frogJumpRecursively(int n) {
if (n == 0 || n == 1) return 1;
return 2 * frogJumpRecursively(n - 1);
}
循環(huán)實現(xiàn)
/**
* 循環(huán)實現(xiàn)
*
* @param n
* @return
*/
public int JumpFloorII(int n) {
if (n == 0 || n == 1) return 1;
int result = 1;
while (n > 1) {
result *= 2;
n--;
}
return result;
}
注意,當(dāng)n > = 2時:
f(n)=2f(n?1)=4f(n?2)=8f(n?3)=...,即
f(n)=f(n?1)=
f(n?2)=
f(n?3)=...=
f(n?(n?1))=
f(1)
所以當(dāng)n > = 2時也可以直接計算
public static int JumpPower2(int n) {
if (n == 0 || n == 1) return 1;
return 1 << (n - 1);
}
參考鏈接: