有一楼梯共m级,刚开始时你在第一级,若每次只能跨上一级或者二级,要走上m级,共有多少走法?注:规定从一级到一级有0种走法。
给定一个正整数int n,请返回一个数,代表上楼的方式数。保证n小于等于100。为了防止溢出,请返回结果Mod 1000000007的值。
测试样例:
3
返回:2
这题用递归的斐波那契数列算***超时:
public int countWays(int n) {
// write code here
if(n==0){
return 0;
}else if(n==1){
return 1;
}else if(n==2){
return 2;
}else{
return countWays(n-1)+countWays(n-2);
}
}
所以可以把他改成动态规划:
public int countWays(int n) {
// write code here
int dp[]=new int [n];
dp[0]=0;
dp[1]=1;
dp[2]=2;
if(n>2){
for(int i=3;i<n;i++){
dp[i]=(dp[i-1]+dp[i-2])%1000000007;
}
}
return dp[n-1];
}
dp[i]表示的是到第i个台阶有多少种跳法。
//设m级台阶有 a[m] 种走法,则有 a[m] = a[m-1] + a[m-2];因为到m阶只可能从m-1 和 m-2 这两个结果走过来。
//题目规定 1级 0 种 走法。2级易得有 1 种走法,3阶 2种。利用动态规划思想可解决问题。
class GoUpstairs {
public:
int countWays(int n) {
int a[100]={0,0,1,2};
for(int i = 4; i <= n; i++)
a[i] = (a[i-1] + a[i-2])%1000000007;
return a[n];
}
}; classGoUpstairs {public:intcountWays(intn) {// write code hereints[101];s[0]=0;s[1]=0;s[2]=1;s[3]=2;for(inti=4;i<=n;i++){s[i]=(s[i-2]+s[i-1])%1000000007;}returns[n];}};
思路:动态规划,从第三级开始,它的结果有第二级和第一级的结果相加得到。 推广到一般,则对于任意i>=3的台阶,它的方法数,从递推方程为: result[i] = result[i - 1] + result[i - 2]; (其中result数组存的是该级的方法数) 考虑到会溢出, 将递推方程修改为: result[i] = result[i - 1] %1000000007+ result[i - 2]%1000000007; import java.util.*; public class GoUpstairs { public int countWays(int n) { if (n == 0) { return 0; } long[] result = new long[n + 1]; result[0] = 0; result[1] = 1; for (int i = 2; i <= n; i++) { result[i] = result[i - 1] %1000000007+ result[i - 2]%1000000007; } return (int)(result[n] % 1000000007); } }
import java.util.*;
/*
在第一级台阶,从第一级到第一级有0种走法,f(1)=0
在第二级台阶,从第一级到第二级有1种走法,f(2)=1
在第三级台阶,从第一级到第三级有2种走法(一次上两级台阶,或一次上一级台阶),f(3)=2
实际就是斐波那契数列,第n级台阶的走法为从第n-1上一级台阶,或从n-2上两级台阶,f(n)=f(n-1)+f(n-2)
(PS:递归复杂度指数级,会超时;所以选择用循环实现,复杂度为O(n))
*/
public class GoUpstairs {
if(n == 1) return 0;
if(n == 2) return 1;
if(n == 3) return 2;
int a=1, b=2, tmp=0;
for(int i=4; i<=n; i++) {
tmp = (a+b)%1000000007;
a = b;
b = tmp;
}
return tmp;
}
}
class GoUpstairs{ typedef vector<long long> vec; typedef vector<vec> mat; public: /* * 快速幂解法 */ int countWays(int n){ n = n-1; if(n<=0){ return 0; } if(n<=2){ return n; } mod = 1000000007; mat base {{1,1}, {1,0}}; mat res = fast_matrix_power(base, n-2); return (2*res[0][0]+res[0][1])%mod; } /* * 平庸解法 */ int cw(int n) { n = n-1; int dp[101]; dp[0] = 0; dp[1] = 1; dp[2] = 2; if (n >= 3) { for (int i = 3; i <= n; i++) { dp[i] = (dp[i - 1] + dp[i - 2]) % mod; } } return dp[n]; } private: int mod; /* * 矩阵快速幂 */ mat fast_matrix_power(mat& m, int p){ mat ans(m.size(), vec(m[0].size(), 0)); // 构造单位矩阵eye for(int i=0; i<ans.size(); i++){ ans[i][i] = 1; } mat base = m; for(; p!=0; p>>=1){ if(p&1){ matrix_mult(ans, base); } matrix_mult(base, base); } return ans; } /* * 矩阵乘法 */ void matrix_mult(mat& m1, mat& m2){ // 对于矩阵维度的处理,仅做最基本的检查 assert(m1[0].size() == m2.size()); int p = m1.size(), q=m1[0].size(), r=m2[0].size(); mat res(p, vec(r, 0)); for(size_t i=0; i<p; i++){ for(size_t j=0; j<r; j++){ for(size_t k=0; k<q; k++){ res[i][j] = (res[i][j] + m1[i][k] * m2[k][j]) % mod; } } } m1.swap(res); } };
// 斐波那契数列
// f(n) = f(n-1) + f(n-2) n>3
import java.util.*;
public class GoUpstairs {
public int countWays(int n) {
// write code here
if(n<=3){
return n-1;
}
int a = 1;
int b = 2;
for(int i=4;i<=n;i++){
b = a + b;
a = b - a;
b = b % 1000000007;
a = a % 1000000007;
}
return b;
}
} 既然你们都用了动态规划,那我分享一个能跑的递归算法
import java.util.*;
public class GoUpstairs {
static int[] num = new int[100];
public static int countWays(int n) {
if(n == 0){
return 0;
}
if(n == 1){
return 0;
}
if(n == 2){
return 1;
}
if(n == 3){
return 2;
}
if(num[n-1] != 0){
return num[n-1];
}
num[n-1] = (countWays(n-1)+countWays(n-2))%1000000007;
return num[n-1];
}
}
//个人觉得应该在最终的结果上Mod,不应该每做一步就Mod,你们觉得呢?
import java.util.*;
public class GoUpstairs {
public int countWays(int n) {
// write code here
//dp[i]=dp[i-1]+dp[i-2]
long[] dp = new long[n+1];
dp[0]=0;
dp[1]=0;
dp[2]=1;
dp[3]=2;
int Mod=1000000007;
for(int i=4;i<=n;i++){
dp[i]=(dp[i-1]+dp[i-2])%Mod; //dp[i]=dp[i-1]+dp[i-2]
}
return (int)dp[n]; //个人觉得应该是这样才对(int)(dp[n]%Mod)
}
}
class GoUpstairs {
public:
long long f[105][105];//f[i][j]表示第i步到达第j个台阶的方法数
long long sum;
int countWays(int n) {
// write code here
for(int i=0;i<=n;i++){
f[1][i] = 0;
}
f[1][1] = 1;
f[1][2] = 1;
for(int i=2; i <=n;i++){//从第二步开始扫描
//我是以0级台阶作为起点的,而题目是以第1级台阶作为起点的,所以j只要扫描到n-1就可以了
for(int j=2;j<=n-1;j++){//从第二级台阶开始扫描,到了第n-1级就停止
f[i][j] = f[i-1][j-1] + f[i-1][j-2];
if( f[i][j]>1000000007){
f[i][j] = ( f[i][j]%1000000007);
}
}
}
sum = 0;
for(int i = 1 ; i <=n;i++){
sum += f[i][n-1];
if(sum>1000000007){
sum = (sum%1000000007);
}
}
return (sum%1000000007);
}
};
// (a+b)%m = (a%m + b%m)%m;
//防止溢出,中间结果mod
class GoUpstairs {
public:
int countWays(int n) {
// write code here
long long a0=0;
long long a1=1;
long long a2;
int i=0;
while(i<n)
{
a2=a0%1000000007l+a1%1000000007l;
a0=a1%1000000007l;
a1=a2%1000000007l;
i++;
}
return a0;
}
};
class GoUpstairs {
public:
//时间复杂度o(n),空间复杂度o(1);
int countWays(int n) {
// write code here
if(n<=1) return 0;
if(n==2) return 1;
if(n==3) return 2;
int pre=1;
int next=2;
int temp;
for(int i=4;i<=n;i++)
{
temp=(pre+next)%1000000007;
pre=next;
next=temp;
}
return temp;
}
};
public int countWays(int n) { int[] s=new int[101]; s[1]=0;s[2]=1;s[3]=2; for(int i=4;i<=n;i++){ s[i]=s[i-1]+s[i-2]; if(s[i]>1000000007) s[i]=s[i]%1000000007; } return s[n]; }