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 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
本题依然采用贪心算法,局部最优就是每次买卖区间内为正数且争取最大,全局最优就是尽可能获得最大利润。因此可以计算两天之间的股票利润。比如 [7,1,5,3,6,4],每天的利润为[-6, 4, -2, 3, -2],因为买卖的区间为第2-3天,第4-5天,总利润为4+3=7。
class Solution {
public int maxProfit(int[] prices) {
int sum=0;
for(int i=0;i<prices.length-1;i++){
int differ=prices[i+1]-prices[i];
if(differ>=0) sum+=differ;
}
return sum;
}
}
55. 跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:
- 输入: [2,3,1,1,4]
- 输出: true
- 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例 2:
- 输入: [3,2,1,0,4]
- 输出: false
- 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
首先要注意审题,每个元素的值表示可以跳跃的最大长度,也就是说可以不选择跳那么多。比如示例1: [2,3,1,1,4],第一个位置最大可以跳2步到位置3,但是也可以选择跳1步到位置2。
该题有一个思路是,当前位置所在的数值,是否大于或等于从当前位置到下一个位置的距离。贪心算法就是,如果每到一个位置,都满足上面的条件,便可以到达最后一个位置。
按照代码随想录的说法,就是每次都移动一步,然后每次移动取最大步数,即最大的覆盖范围。最后得到整体的最大覆盖范围。
每次下标i都在cover的范围内移动,每移动一个元素,cover就会进行判断是否当前元素覆盖的范围大于之前的cover值,如果大于则更新cover,如果cover大于或等于最后一个元素的下标,则表示可以达到最后的位置。
本题重要的是要想明白:其实跳几步无所谓,关键在于可跳的覆盖范围!这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点!
class Solution {
public boolean canJump(int[] nums) {
int cover=nums[0];
if(nums.length==1) return true;
for(int i=0;i<=cover;i++){
cover=Math.max(cover, nums[i]+i);
if(cover>=nums.length-1) return true;
}
return false;
}
}
45.跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
- 输入: [2,3,1,1,4]
- 输出: 2
- 解释: 跳到最后一个位置的最小跳跃数是 2。从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明: 假设你总是可以到达数组的最后一个位置。
本题和跳跃游戏I的区别在于,加上了对于跳跃次数的限制,并且题设一定可以到达最后一个位置。上一题中,我们总结重要的是要看覆盖的范围并且进行更新,这次我们关键是要看什么时候给步数+1,最直接的想法就是每次都走当前位置所能覆盖的最大步数。如果移动的下标达到了当前覆盖的最远下标,步数就加一。
class Solution {
public int jump(int[] nums) {
int count=0;
int cover=nums[0];
int index=0; //记录当前覆盖的最远距离下标
if(nums.length==1||nums.length==0||nums==null) return 0;
for(int i=0;i<nums.length;i++){
cover=Math.max(nums[i]+i, cover);
//若当前元素最大覆盖范围可以到达最后一个元素,+1并跳出
if(cover>=nums.length-1){
count++;
break;
}
//若目前还不能到达最后一个元素,则跳到下一个最远的位置
if(i==index) {
index=cover;//让元素移动到上一个元素所能覆盖的最远的位置
count++;
}
}
return count;
}
}
注意⚠️:在编写的时候,我将判断是否到达最后一个元素的逻辑放到了让元素移动的逻辑之后,这会导致多走一步。