导语
leetcode刷题笔记记录,本篇博客是贪心部分的第二期,主要记录题目包括:
Leetcode 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 。
提示:
1 <= prices.length <= 3 * 10^4
0 <= prices[i] <= 10^4
解法
使用贪心算法的思路,我们需要往最终结果中添加正向收益即可,最终利润是可以分解为每天为单位的维度,而不是整体去考虑,那么每天的利润序列为:
所以,只需要通过计算每天的正向收益,就可以得到最大的总收益。具体代码如下:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
result = 0
for i in range(1, len(prices)):
result += max(0, prices[i]-prices[i-1])
return result
Leetcode 55 跳跃游戏
题目描述
给你一个非负整数数组 nums
,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回 true
;否则,返回 false
。
示例 1:
输入: nums = [2,3,1,1,4]
输出: true
解释: 可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
提示:
1 <= nums.length <= 10^4
0 <= nums[i] <= 10^5
解法
这道题目如果使用模拟将所有情况遍历,则非常复杂。实际上,这里只需要判断是否能够到达,所以转化为跳跃的覆盖范围!w这道题目如果使用模拟将所有情况遍历,则非常复杂。实际上,这里只需要判断是否能够到达,所以转化为跳跃的覆盖范围! 无需明确一次究竟跳几步,每次取最大的跳跃步数,这个就是可以跳跃的覆盖范围。
设计程序,每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。对应的贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。
具体代码如下:
class Solution:
def canJump(self, nums: List[int]) -> bool:
# 特殊情况处理:只有一个元素的数组可以认为总是可以到达
if len(nums) == 1:
return True
# cover表示当前能够跳到的最远位置,i是当前正在检查的位置
cover, i = 0, 0
# 只要当前的位置i在能到达的最远距离cover内,就继续检查
while i <= cover:
# 对于位置i,能够跳到的最远距离是i+nums[i],更新cover为最大的那个值
cover = max(i + nums[i], cover)
# 如果cover已经大于或等于数组的最后一个位置,说明可以到达最后,返回True
if cover >= len(nums) - 1:
return True
# 继续检查下一个位置
i += 1
# 如果循环结束后仍没有返回True,说明不能到达数组的最后一个位置,返回False
return False
Leetcode 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 步到达数组的最后一个位置。
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
- 题目保证可以到达
nums[n-1]
解法
相比于上一题,本题需要求出最少的步数,因此,实际上还是求得最大覆盖范围,只不过这次需要我们统计跳了几次。这里需要统计两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖。示意图参考代码随想录
完整代码如下:
class Solution:
def jump(self, nums: List[int]) -> int:
# 如果只有一个元素,那么我们已经在目的地了,因此不需要任何跳跃
if len(nums) == 1:
return 0
# cur_distance: 从起点到当前能够到达的最远距离
# next_distance: 当前元素及之前的元素可以到达的最远距离
cur_distance, next_distance = 0, 0
# 跳跃次数
result = 0
# 遍历数组元素
for i in range(len(nums)):
# 更新next_distance为当前元素可以到达的最远距离与之前的next_distance中的较大值
next_distance = max(i + nums[i], next_distance)
# 如果遍历到了当前可达的最远距离
if i == cur_distance:
# 如果当前距离不是数组的最后一个位置
if cur_distance != len(nums) - 1:
# 增加跳跃次数
result += 1
# 更新当前的最远距离为下一步的最远距离
cur_distance = next_distance
# 如果已经可以到达数组的最后位置,则提前跳出循环
if cur_distance >= len(nums) - 1:
break
return result