1.剑指 Offer 10- I. 斐波那契数列
初步思路:题知条件已经给出了递归公式,采用递归做这题无疑,于是写下了如下代码:
class Solution {
public:
int fib(int n) {
//边界条件
if(n == 0) return 0;
if(n == 1) return 1;
//递归
return (fib(n - 1) + fib(n - 2)) % 1000000007;
}
};
喜提超时。
总结的原因是有这种方法有大量的重复计算,如 fib(n) 和 fib(n - 1) 均需要计算 fib(n - 2)。
在上一个方法的基础上,既然从 fib(n) 向下计算会发生大量重复计算,那么从 fib(0) 向 fib(n)计算即可解决这样的问题。
修改代码如下:
class Solution {
public:
int fib(int n) {
//边界条件
if(n == 0) return 0;
if(n == 1) return 1;
int ans = 0, A = 0, B = 1;
for(int i = 2; i <= n ; i++){
ans = (A + B) % 1000000007;
A = B;
B = ans;
}
return ans;
}
};
通过了且效率很高。
2.剑指 Offer 10- II. 青蛙跳台阶问题
注:关于讨论可能性的问题大都含有递归的性质
关于递归的问题,我们要考虑边界条件与递归法则
边界条件:
即numWays(0) = 1, numWays(1) = 1;
递归法则:
青蛙最后一次运动有两种可能性,跳一步或者两步,那么青蛙到达最后一步前所位置的可能性种数为numWays(n - 1)或者numWays(n - 2),分别对应最后跳一步或者两步。
那么很好理解numWays(n) = numWays(n - 1) + numWays(n - 2);
分析到此发现,这道题与斐波那契数列十分相似,只有numWays(0) = 1的改变。
得到如下代码:
class Solution {
public:
int numWays(int n) {
//边界条件
if(n == 0) return 1;
if(n == 1) return 1;
int ans = 0, A = 1, B = 1;
for(int i = 2; i <= n ; i++){
ans = (A + B) % 1000000007;
A = B;
B = ans;
}
return ans;
}
};
3.剑指 Offer 63. 股票的最大利润
动态规划思考过程(from Krahets):
状态定义:设 dp[i] 为以price[i] 结尾所能获取利润的最大值,即前 i 天的最大利润;
转移方程:那么很好想到dp[i] 应该为 dp[i - 1] 与第 i 天卖出的最大值;即有 dp[i] = max( dp[i - 1], price[i] - min(price[0 : i]));
初始状态:dp[0] = 0;
返回值:dp[n - 1] 其中n为数组长度。
根据如上思路,可得到如下代码:其中minValue用于在遍历过程中记录前 i 项的最小值
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size() == 0 || prices.size() == 1)
return 0;
int ans = 0, temp = 0;
int minValue = prices[0];
for(int i = 1 ; i < prices.size(); i++){
if(i == 1 || prices[i - 1] < minValue)
minValue = prices[i - 1];
temp = prices[i] - minValue;
ans = ans > temp ? ans : temp;
}
return ans;
}
};