贪心算法的本质是选择每一阶段的局部最优,从而达到全局最优。
贪心一般解题步骤:
- 将问题分解为若干个子问题
- 找出适合的贪心策略
- 求解每一个子问题的最优解
- 将局部最优解堆叠成全局最优解
LeetCode 455. 分发饼干
先将小孩胃口和饼干大小排序,因为默认从小到大排序,为了代码方便,我们选择小饼干满足小胃口的策略。先拿最小的饼干给胃口最小的小孩,如果满足就继续后面的饼干和小孩,如果不满足这块饼干就不行了,换大一点的饼干。
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
g.sort()
s.sort()
result = 0
i, j = 0, 0
while i < len(g) and j < len(s):
if g[i] <= s[j]:
result += 1
i += 1
j += 1
else:
j += 1
return result
LeetCode 376. 摆动序列
力扣题目链接
本题把图画出来会好理解一些
让峰值尽可能的保持峰值,然后删除单一坡度上的节点
在计算是否有峰值的时候,大家知道遍历的下标 i ,计算 prediff(nums[i] - nums[i-1])
和 curdiff(nums[i+1] - nums[i])
,如果prediff < 0 && curdiff > 0
或者 prediff > 0 && curdiff < 0
此时就有波动就需要统计。
这是我们思考本题的一个大题思路,但本题要考虑三种情况:
- 情况一:上下坡中有平坡
- 情况二:数组首尾两端
- 情况三:单调坡中有平坡
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
if len(nums) == 1:
return 1
prediff = 0
result = 1
for i in range(len(nums)-1):
curdiff = nums[i+1] - nums[i]
if (prediff >= 0 and curdiff < 0) or (prediff <= 0 and curdiff > 0):
result += 1
# 当出现摆动时,才更新prediff,可以绕过单调平坡的情况
prediff = curdiff
return result
LeetCode 53. 最大子序和
力扣题目链接
如果当前子数组的和小于0,说明它会拉低后面子数组的和,那么应该抛弃它,从下一个数开始求和
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
cur_sum = 0
result = -float('inf')
i = 0
while i < len(nums):
cur_sum += nums[i]
if cur_sum < 0:
result = max(result, cur_sum)
cur_sum = 0
else:
result = max(result, cur_sum)
i += 1
return result
LeetCode 122. 买卖股票的最佳时机II
力扣题目链接
股票价格如果有增加就在增加之前买入,有下降就在下降之前卖出。实现代码的逻辑就是如果后一天的价格比前一天高,高出来的部分就加入到利润中,如果低就不算。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
profit = 0
for i in range(1, len(prices)):
if prices[i] >= prices[i-1]:
profit += (prices[i] - prices[i-1])
return profit
LeetCode 55. 跳跃游戏
力扣题目链接
如果本题去思考每次跳几步,下次再跳几步,就把问题搞复杂了。
本题只需考虑能跳跃到的最远位置,只要能跳过去就好,至于怎么跳过去的不重要。如果最后的跳跃范围覆盖了终点,那么就可以跳过去,否则就不行。
class Solution:
def canJump(self, nums: List[int]) -> bool:
farest = 0
for i in range(len(nums)):
if farest >= i:
farest = max(farest, i + nums[i])
return farest + 1 >= len(nums)