一、理论基础
1. 什么是贪心
贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
2. 贪心的解题步骤
- 将问题分解为若干个子问题
- 找出适合的贪心策略
- 求解每一个子问题的最优解
- 将局部最优解堆叠成全局最优解
二、455.分发饼干
1. 解题思路
尽量用最大的饼干去满足胃口大的孩子。
2. 代码实现
(1)因为是用大饼干满足胃口大的孩子,所以对饼干、孩子胃口数组排序。定义一个result变量,用于记录喂饱了多少个小孩。
(2)从大到小遍历(从后向前遍历):接下来用while去控制饼干的从大到小遍历,每一个饼干需要从大到小投喂给某一个孩子,所以如果投喂不了某个孩子,孩子胃口数组会继续向前遍历,而饼干不动,因此只能使用while循环而不是for循环。while循环条件是index>=0(防止抛出异常)并且饼干大于等于孩子胃口时,result才做加1,然后index减1,向前移动一位。
(3)最后返回result。
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
result = 0
g.sort()
s.sort()
j = len(s) - 1
for i in range(len(g)-1, -1, -1):
if j >= 0 and s[j] >= g[i]:
result += 1
j -= 1
return result
3. 常见误区
外层必须遍历胃口,内层饼干,不可以颠倒。
因为外层是饼干而里层是胃口的话,那么饼干会一直向前走,而胃口是动态移动的,饼干一直喂不了,会前移,而胃口会一直停在末尾不动,最后饼干结束了,result等于0。
三、376. 摆动序列
代码实现
(1)如果nums的大小等于1,那么直接返回1即可。
(2)定义变量prediff初始为0;curdiff也初始为0;result默认为1,因为默认最右端有一个坡度。
(3)for循环,注意 i 不用遍历到最后一个元素,因为已经默认有一个坡度,所以 i 只需要遍历到nums长度-2的位置。
curdiff等于nums[i+1]减去nums[i],即后一个元素减去当前元素。接下来判断是否出现波动,1)如果prediff大于等于0,同时curdiff小于0;
2)或如果prediff小于等于0,同时curdiff大于0;
那么满足上述两种情况任一情况都属于出现波动,所以此时result加1。
(4)使用完成curdiff后,就用curdiff指向prediff。
(5)注意:以上代码忽略了单调平坡的情况,所以需要更改代码(4),原本代码 (4)是使prediff紧跟curdiff,将其修改为当出现摆动才去修改prediff的位置,将(4)放在if下方,这样才可以绕过单调有平坡的情况。
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
if len(nums) <= 1:
return len(nums)
result = 1
curdiff = 0
prediff = 0
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 = curdiff
return result
四、53. 最大子序和
1. 解题思路
当连续和为负数时,就抛弃连续和,从下一个位置作为起点寻找连续和最大的子序列。注意不是说遇到负数就抛弃连续和,而是说遇到连续和为负数才抛弃当前连续和。
2. 代码实现
(1)定义一个变量result 用于记录连续和中的最大值,所以要初始化为一个最小值。定义count用于更新连续和,初始化为0。
(2)for循环遍历数组,所以连续和数组count进行累加;如果count大于result,那么将result进行更新;当count小于0时,就将count更新为0,从下一个新位置开始累加连续和。
(3)最后返回result即可。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
count = 0
result = float('-inf')
for i in range(len(nums)):
count += nums[i]
if count > result:
result = count
if count < 0:
count = 0
return result