122.买卖股票的最佳时机II
-
题意:给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1: 输入: [7,1,5,3,6,4] 输出: 7 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 示例 2: 输入: [1,2,3,4,5] 输出: 4 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 示例 3: 输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
-
思路:计算一段时间的利润比如第1天到第3天,可以用第1天利润+第2天利润+第三天利润计算。这样每天的利润是正的话,最后累加的利润只会越来越大。如果当天利润为负,只会拖累总利润和。这就用了贪心算法局部最优达到整体最优的结果。
计算每一天的利润,第0天买入,第1天卖出,此时就有第一天的利润了。利润为正数时就记录到res中,如果当天利润为负数就不计入(既不买入卖出)。
代码简单,但是数学的思路比较难想的到和想的清楚。
class Solution {
public int maxProfit(int[] prices) {
int res = 0;
int dayPrice = 0;
for(int i = 1; i < prices.length; i++) {
dayPrice = prices[i] - prices[i - 1];
if(dayPrice > 0) {
res += dayPrice;
}
}
return res;
}
}
55. 跳跃游戏
-
题意:给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1: 输入:nums = [2,3,1,1,4] 输出:true 解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。 示例 2: 输入:nums = [3,2,1,0,4] 输出:false 解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
-
思路:不去纠结每个元素到底往后跳几步合适,而是看每个元素能覆盖到的最大范围。
问题就转化为了跳跃覆盖范围是否可以覆盖到终点
局部最优:每次移动都去元素能跳跃的最大步数,即得到最大的覆盖范围。
整体最优:最终得到整体最大的覆盖范围,看是否能到达终点。
class Solution {
public boolean canJump(int[] nums) {
//每个元素向后走能覆盖到的范围
int cover = 0;
//如果数组长度为1,直接就在终点,返回true即可。
if(nums.length == 1) {
return true;
}
//i在cover范围内移动,每移动一次,得到该元素对cover的补充
for(int i = 0; i <= cover; i++) {
//cover要取原来的cover和补充后的cover的最大值
cover = Math.max(i + nums[i], cover);
//如果cover覆盖到最后一个元素位置了,即能跳到最后返回true
if(cover >= nums.length - 1) {
return true;
}
}
return false;
}
}
45.跳跃游戏II
-
题意:给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。
每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:
0 <= j <= nums[i]
i + j < n返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。
示例 1: 输入: nums = [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 示例 2: 输入: nums = [2,3,0,1,4] 输出: 2
-
思路:
局部最优:当前可移动距离尽可能多走,如果还没到终点,步数再加一。
整体最优:一步尽可能多走,从而达到最小步数。这里需要统计两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖。
如果移动下标达到了当前这一步的最大覆盖最远距离了,还没有到终点的话,那么就必须再走一步来增加覆盖范围,直到覆盖范围覆盖了终点。
class Solution {
public int jump(int[] nums) {
int curCover = 0;
int nextCover = 0;
int res = 0;
if(nums.length == 1) {
return 0;
}
for(int i = 0; i <= nums.length; i++) {
//记录下一步能到达得最远范围
nextCover = Math.max(nextCover, i + nums[i]);
//如果此时下一步能覆盖最远范围,即到达终点,res++后break即可。
if(nextCover >= nums.length - 1) {
res++;
break;
}
//如果当前的curCover遍历完了还没覆盖到终点,就要启动下一步了,下一步选取遍历上一步curCover时能达到得最远距离。
if(i == curCover) {
curCover = nextCover;
res++;
}
}
return res;
}