一、力扣题122. 买卖股票的最佳时机 II
给你一个整数数组 prices
,其中 prices[i]
表示某支股票第 i
天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4] 输出:7 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。 总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
提示:
1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104
这道题的题解确实很巧妙。我一开始想的方向是类似摆动序列那样的,寻找到锋值和谷值,但试了一下发现太麻烦了,有很多需要注意的点。
事实上,要求取最大利润,只需要将这个数组中,所有单调递增的部分加在一起就好了,这样就是最大利润,出乎意料的简单。
function maxProfit($prices) {
if(count($prices) == 1) return 0;
$sum = 0;
for($i = 1; $i < count($prices); $i++) {
if($prices[$i] > $prices[$i - 1]) {
$sum += $prices[$i] - $prices[$i - 1];
}
}
return $sum;
}
二、力扣题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 , 所以永远不可能到达最后一个下标。
提示:
1 <= nums.length <= 3 * 104
0 <= nums[i] <= 105
这道题也是看了题解后才清楚的。这道题的本质是求当前可跳跃的最远范围,不需要考虑具体的策略和搭配选择,只要清楚在这些元素中,有一种组合能达到跳跃的最远范围就好了,不需要考虑这个组合具体是什么。
例如[ 3, 3, 3, 1, 3, 1],在 0 的位置可跳跃的最远位置是 3 + 0,所以能继续选择小于等于位置 3 元素,在 1 的位置可跳跃的最远位置是 3 + 1 ,4 > 3, 所以在 [ 0, 1]的范围内能达到的最远距离是 4。接下来是位置 2,跳跃的最远位置是 3 + 2,已经能跳跃到数组的尾端了,true。
而如果最远位置就是自己现在遍历到的元素位置(不是最后一个元素),则说明无法到达。
function canJump($nums) {
$max = $nums[0];
for($i = 0; $i <= $max && $i < count($nums); $i++) {
$max = max($i + $nums[$i], $max);
if($max >= count($nums) - 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
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
- 题目保证可以到达
nums[n-1]
这道题和上一道题本质是相同的,都离不了求最远范围。遍历最远范围内没遍历过的所有元素,找到这些元素中最大的最远范围,然后跳到这个元素上,又一次遍历新的最远范围里没遍历过的所有元素。
function jump($nums) {
if(count($nums) == 1) return 0;
$sum = $nums[0]; //最远范围大小
$sub = 0; //每次循环开始的下标
$num = 1; //最小跳跃次数
$max = $sub; //具有最远范围的元素下标
while($sum < count($nums) - 1) {
for($i = $sub + 1; $i <= $sum; $i++) {
if($i + $nums[$i] > $max + $nums[$max]) {
$max = $i;
}
}
$sub = $sum;
$sum = $max + $nums[$max];
$num++;
}
return $num;
}