目录
-
斐波那契数列(剑指欧肥儿)
题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39
解题代码一(常规方法):
class Solution {
public:
int Fibonacci(int n) {
//排除不可能
if(n > 39) return 0;
//变量
int first = 0;
int second = 1;
int result;
if(n == 0) return 0;
if(n == 1) return 1;
//生成
for(int i = 2;i <= n;i++){
result = first + second;
first = second;
second = result;
}
return result;
}
};
解题思路:
- 一般的裴波那契数列都是以1,1为前两个数,这道题明确表明了是以0项的0数字开头,那么我们默认为这个裴波那契数列的前两个是(0,1)
- 这道题是最常见的思路,我们把0项和1项作为特殊情况放在前面讨论。
解题代码二(动态规划):
class Solution {
public:
int Fibonacci(int n) {
int first = 0, second = 1;
while(n--) {
second += first;
first = second - first;
}
return first;
}
};
解题思路:
- 这道题采用动态规划比较高级,节省了空间,但是思考起来比较复杂,这个方法可以记下来。
- 这个代码和第一个代码相比,不用把0项和1项拿出来单独讨论
- n--也对应的是return first,如果是n++对应return second
-
跳台阶(剑指欧肥儿)
题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
解题代码一:(运用裴波那契数列,采用上一道题的动态规划方法)
class Solution {
public:
int jumpFloor(int number) {
int first = 1;
int second = 2;
while(--number){
second +=first;
first = second - first;
}
return first;
}
};
解题思路: 见裴波那契数列的解题代码二的解题思路。
解题代码二:(递归方法)
class Solution {
public:
int jumpFloor(int number) {
if(number <= 0){return 0;}
else if(number == 1){return 1;}
else if(number == 2){return 2;}
else{
return jumpFloor(number-1)+jumpFloor(number-2);
}
}
};
解题思路:
- 这个思路用递归的方法来做的,我们可以举一反三,如果青蛙一次可以跳1,2,3阶,那么最后的应该是return jumpFloor(number-1)+jumpFloor(number-2) + jumpFloor(number-3);如果是一次跳(1,2,3阶)或(1,2,3,4阶)或(1,2,3,4,5·····n阶)我们都可以把最后的return 写出来。这就是裴波那契的变体。这道题是f(n)=f(n-1)+f(n-2),下道题就可能是f(n)=f(n-1)+f(n-2)+f(n-3)·····,所以我们要掌握这个裴波那切变体的思想。
- 其次是时刻不能忘记递归思想。
-
变态跳台阶(剑指欧肥儿)
题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题代码一:
#include<cmath>
class Solution {
public:
int jumpFloorII(int number) {
int first = 1;
int second = 2;
if(number == 0) {return 0;}
else if(number == 1) {return 1;}
else{
return pow(2,number-1);
}
}
};
解题思路:
- 这是最简单的方法的,就是直接从数字中发现规律,从第0阶台阶跳到第1,2,3,4,5,6······n的台阶的方法分别是1,2,4,8,16,32····2(n-1)种方法,也就是说每跳一个台阶的方法个数是跳前面所有台阶的方法个数的总和,于是我们可以得到对跳上n阶台阶的方法个数的通项公式为 2^(n-1)。
- 这是裴波那契数列的变体之一。
解题代码二:
class Solution {
public:
int jumpFloorII(int number) {
int first = 1;
int second = 2;
if(number == 0) {return 0;}
else if(number == 1) {return 1;}
else{
return 2*jumpFloorII(number - 1);
}
}
};
解题思路:思路和代码一相同,但是不用引用cmath的库。
解题代码三:
class Solution {
public:
int jumpFloorII(int number) {
int a = 1;
return a<< (number - 1);
}
};
解题思路:
- 位运算操作更快
- 左移1位(x << 1)就是乘以一个2,在1基础上左移number-1位就是1乘以2^(number-1)
- 不用引用cmath库,这个方法非常强
-
矩形覆盖(剑指欧肥儿)
题目描述:我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
解题代码一(动态规划方法):
class Solution {
public:
int rectCover(int number) {
int first = 1;
int second = 2;
//排除不可能
if(number == 0) return 0;
while(--number){
second += first;
first = second - first;
}
return first;
}
};
解题思路:
- 拿到题目后,计算n=1,2,3,4,5···等到规律,发现是第一二项为1,2的裴波那契数列。
- 在排除n=0的情况下(必须排除,不然测试用例n=0时,代码不会通过),我们运用前几道题的动态规划的解题思路得到此代码。
解题代码二(常规的递归方法):
class Solution {
public:
int rectCover(int number) {
int first = 1;
int second = 2;
//排除不可能
if(number <= 0) return 0;
else if(number == 1) return first;
else if(number == 2) return second;
else{
return rectCover(number - first) + rectCover(number - second);
}
}
};
解题思路:见跳台阶的方法二的解题思路。