122. 买卖股票的最佳时机II
本题解法很巧妙,大家可以看题思考一下,在看题解。文章链接:代码随想录
重点:
1. 如果想到其实最终利润是可以分解的,那么本题就很容易了!
如何分解呢?
假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。
相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。
2. 局部最优:收集每天的正利润,全局最优:求得最大利润。
思路:
1. 初始化result
int result = 0;
2. 拆分利润为每天利润,再只收集正利润
for (int i = 1; i < prices.length; i++) { result += Integer.max(prices[i] - prices[i - 1], 0); }
public int maxProfit(int[] prices) {
int result = 0;
for (int i = 1; i < prices.length; i++) {
result += Integer.max(prices[i] - prices[i - 1], 0);
}
return result;
}
55. 跳跃游戏
本题如果没接触过,很难想到,所以不要自己憋时间太久,读题思考一会,没思路立刻看题解文章链接:代码随想录
重点:
1. 跳跃覆盖范围究竟可不可以覆盖到终点!
2. 贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。
3. 这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。
思路:
1. 初始化覆盖范围,当nums长度为1时,直接返回true
int cover = 0; if (nums.length == 1) { return true; }
2. 循环遍历数组,不断更新cover为最大的cover,当能够覆盖数组到最后一个元素时,返回true
// 注意这里是小于等于cover for (int i = 0; i <= cover; i++) { // 不断更新cover为最大的覆盖范围 cover = Math.max(i + nums[i], cover); // 覆盖到终点了或者甚至超过终点了 if (cover >= nums.length - 1) { return true; } }
public boolean canJump(int[] nums) {
int cover = 0;
if (nums.length == 1) {
return true;
}
// 注意这里是小于等于cover
for (int i = 0; i <= cover; i++) {
// 不断更新cover为最大的覆盖范围
cover = Math.max(i + nums[i], cover);
// 覆盖到终点了或者甚至超过终点了
if (cover >= nums.length - 1) {
return true;
}
}
return false;
}
45. 跳跃游戏II
本题同样不容易想出来。贪心就是这样,有的时候 会感觉简单到离谱,有时候,难的不行,主要是不容易想到。文章链接: 代码随想录重点:
1. 局部最优:当前可移动距离尽可能多走,如果还没到终点,步数再加一。整体最优:一步尽可能多走,从而达到最少步数。
2. 两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖。以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点。
思路:
1. 初始化当前覆盖范围,下一步的最大覆盖范围,result
// 当前覆盖范围的最远距离下标 int curCover = 0; // 下一步覆盖范围的最远距离下标 int nextCover = 0; int result = 0;
2. 循环遍历当前的覆盖范围,不断更新下一步覆盖范围为最大范围。当前覆盖范围走完之后,说明已经走了一步,需要进入下一步,更新当前覆盖范围为下一步的最大范围。如果当前覆盖范围最远到达终点,直接break。注意,一开始curCover为0,刚刚进入这个for的时候就会进入if里了。
for (int i = 0; i < nums.length; i++) { // 更新下一步覆盖范围为最大的覆盖范围 nextCover = Math.max(i + nums[i], nextCover); // 遇到当前覆盖范围的最远距离下标 if (i == curCover) { // 已经走了一步 result++; // 更新当前覆盖范围(相当于进入下一步) curCover = nextCover; // 当前覆盖范围最远到达终点,直接break if (nextCover >= nums.length - 1) { break; } } }
public int jump(int[] nums) {
if (nums.length == 1) {
return 0;
}
// 当前覆盖范围的最远距离下标
int curCover = 0;
// 下一步覆盖范围的最远距离下标
int nextCover = 0;
int result = 0;
for (int i = 0; i < nums.length; i++) {
// 更新下一步覆盖范围为最大的覆盖范围
nextCover = Math.max(i + nums[i], nextCover);
// 遇到当前覆盖范围的最远距离下标
if (i == curCover) {
// 已经走了一步
result++;
// 更新当前覆盖范围(相当于进入下一步)
curCover = nextCover;
// 当前覆盖范围最远到达终点,直接break
if (nextCover >= nums.length - 1) {
break;
}
}
}
return result;
}