求斐波那契数列第N项,最简单的方法
int f(int n)
{
if(n <= 2) return 1;
return f(n - 1) + f(n - 2);
}
但显然这很低效,因为会重复计算很多次前面的值,比如算f(10),要得到f(9),和f(8),而求f(9)要求f(8) 和f(7),求f(8)要求f(7)和f(6),就重复计算了f(8)和f(7),越往后重复的越多,总复杂度为指数级,效率极低
我们可以将前面的计算结果存起来,避免重复计算
int f(int n)
{
int* arr = new int[n];
arr[0] = 1;
arr[1] = 1;
for(int i = 2;i < n;i++)
{
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr[n - 1];
}
这样效率虽高,但占用额外的空间,仔细想想,每次结果只与前两次结果有关,可以优化优化
int f(int n)
{
if(n <= 2) return 1;
int first = 1;
int second = 1;
int ans;
for(int i = 3;i <= n;i++)
{
ans = first + second;
first = second;
second = ans;
}
return ans;
}
这被称为迭代,无论是在时间上还是在空间上都很高效。
运用上述思想,来看下经典的爬楼梯问题
题目描述
假设你正在爬楼梯。需要 n 阶你才能到达楼顶
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
4. 1 阶 + 1 阶 + 1 阶
5. 1 阶 + 2 阶
6. 2 阶 + 1 阶
法一
//方法一,记忆化递归
int ans(int i,int n,int arr[])
{
if(i > n)
return 0;
if(i == n)
return 1;
if(arr[i] > 0)
return arr[i];
arr[i] = ans(i + 1,n,arr) + ans(i + 2,n,arr);
return arr[i];
}
int climbStairs(int n)
{
int* arr = new int[n];
for(int i = 0;i < n;i++)
{
arr[i] = 0;
}
return ans(0,n,arr);
}
法二
int climbStairs(int n) {
int* arr = new int[n];
if(n == 1)
return 1;
arr[0] = 1;
arr[1] = 2;
for(int i = 2;i < n;i++)
arr[i] = arr[i -1] + arr[i - 2];
return arr[n - 1];
}
法三
int climbStairs(int n) {
if(n <= 2)
return n;
int first = 1;
int second = 2;
int third;
for(int i = 3;i <= n;i++)
{
third = first + second;
first = second;
second = third;
}
return third;
}