回溯结束,开始贪心算法。
说是贪心没啥规律,不会就去看题解
理论基础
贪心的本质
贪心 = 每一步都选局部最优 → 最终达到全局最优
-
局部最优:当前这一步能拿到的最好结果
-
全局最优:整个问题的最终最优解
-
不回头、不反悔、不看未来,只选当下最好
什么时候能用贪心
满足一条就能试贪心:
-
局部最优可以推出全局最优
-
举不出反例(找不到让贪心失效的情况)
-
问题不能用动态规划(比如背包问题不能用贪心)
贪心有没有套路?
没有固定模板、没有固定公式!
-
不像回溯 / DFS 有标准框架
-
贪心靠常识 + 模拟 + 举反例
-
面试不需要数学证明,能自圆其说即可
贪心通用解题四步
-
把问题拆成一步一步的小决策
-
想清楚:每一步的局部最优是什么
-
按局部最优去做选择
-
验证:这样做能不能得到全局最优(举反例)
455.分发饼干
思路
感觉简单吧,又写不对,提交通过了17个
python
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
count=0
for i in g:
if i in s:
count+=1
return min(count,len(s))
好吧,没我想的那么简单,还要用双指针
小饼干喂胃口小的,大饼干喂胃口大的,能喂就喂,不能喂就跳过。
步骤
-
把孩子胃口
g和饼干s都从小到大排序 -
用两个指针分别指向当前孩子、当前饼干
-
饼干 ≥ 胃口 → 喂饱,两个指针都后移
-
饼干 < 胃口 → 饼干太小,换更大的
提交

python
from typing import List
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
g.sort()
s.sort()
i = j = res = 0
while i < len(g) and j < len(s):
if s[j] >= g[i]:
res += 1
i += 1
j += 1
else:
j += 1
return res
376. 摆动序列
思路
我的第一版错误代码
python
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
minus=[]
for i in range(len(nums)-1):
minus.append(nums[i+1]-nums[i])
count=0
for i in range(len(minus)-1):
if minus[i]*minus[i+1]<0:
count+=1
else:
break # 这里大错特错!不能停!
return count+2
-
只要遇到不摆动就 break,直接停了
-
边界处理错误全递增、全递减、全 0 会算错。
正确思路:
1.处理短数组
python
if len(nums) <= 1:
return len(nums)
-
数组长度 0 → 0
-
长度 1 → 1这是边界条件。
2.计算相邻差值,并去掉 0
python
for i in range(len(nums)-1):
diff = nums[i+1] - nums[i]
if diff != 0:
minus.append(diff)
-
差值 = 后 - 前
-
=0 的不要(平坡不算摆动)
-
最后得到一个只有正数、负数的差值列表
3. 如果全是平坡,返回 1
python
if not minus:
return 1
4. 统计正负交替的次数
python
count = 0
for i in range(len(minus)-1):
if minus[i] * minus[i+1] < 0:
count += 1
-
两个数相乘 < 0 → 一正一负,交替了!
-
每交替一次,count + 1
5. 最终答案 = 交替次数 + 2
-
统计了 count 次交替
-
最终长度 = 交替次数 + 第一个数 + 第二个数 = count + 2
提交

python
from typing import List
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
if len(nums) <= 1:
return len(nums)
minus = []
for i in range(len(nums)-1):
diff = nums[i+1] - nums[i]
if diff != 0: # 跳过平的
minus.append(diff)
if not minus:
return 1
count = 0
for i in range(len(minus)-1):
# 正负交替就计数
if minus[i] * minus[i+1] < 0:
count += 1
return count + 2
53. 最大子序和
题目链接 53. 最大子数组和 - 力扣(LeetCode)
思路
正确思路(Kadane 算法)
核心一句话:当前数字,要么加入前面的子数组,要么自己重新开始一段。
具体规则:
- 维护一个
current_max:表示以当前位置结尾的最大子数组和 - 维护一个
global_max:记录遍历过程中出现过的最大值 - 对每个数:
current_max = max(nums[i], current_max + nums[i])global_max = max(global_max, current_max)
为什么?
- 如果前面的和是负的,加上我只会更小 → 我自己重新开始
- 如果前面的和是正的,加上我会更大 → 加入前面
示例
nums = [-2,1,-3,4,-1,2,1,-5,4]
- current_max = -2, global_max = -2
- 1 → max(1, -2+1= -1) → current=1, global=1
- -3 → max(-3, 1-3=-2) → current=-2, global=1
- 4 → max(4, -2+4=2) → current=4, global=4
- -1 → max(-1, 4-1=3) → current=3, global=4
- 2 → max(2, 3+2=5) → current=5, global=5
- 1 → max(1,5+1=6) → current=6, global=6
- -5 → max(-5,6-5=1) → current=1, global=6
- 4 → max(4,1+4=5) → current=5, global=6
最终返回 6
提交

python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
current_max = global_max = nums[0]
for num in nums[1:]:
# 要么自己重新开始,要么接上前面
current_max = max(num, current_max + num)
# 更新全局最大
global_max = max(global_max, current_max)
return global_max