wuyijia

导航

代码随想录算法训练营-贪心算法-1|455. 分发饼干、376. 摆动序列、53. 最大子数组和、122. 买卖股票的最佳时机 II

1.贪心算法一般分为如下四步:

  • 将问题分解为若干个子问题
  • 找出适合的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优解

 455. 分发饼干

1. 局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)

2.  for 控制 胃口,里面的 if 控制饼干。

3. 技巧:用了一个 index 来控制饼干数组的遍历,遍历饼干并没有再起一个 for 循环,而是采用自减的方式。

 1 class Solution:
 2     def findContentChildren(self, g, s):
 3         g.sort()  # 将孩子的贪心因子排序
 4         s.sort()  # 将饼干的尺寸排序
 5         index = len(s) - 1  # 饼干数组的下标,从最后一个饼干开始
 6         result = 0  # 满足孩子的数量
 7         for i in range(len(g)-1, -1, -1):  # 遍历胃口,从最后一个孩子开始
 8             if index >= 0 and s[index] >= g[i]:  # 遍历饼干
 9                 result += 1
10                 index -= 1
11         return result

376. 摆动序列

1. 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。

2. 局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值。

3. 整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列。

4. 只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)

本题要考虑三种情况:

  1. 情况一:上下坡中有平坡
  2. 情况二:数组首尾两端
  3. 情况三:单调坡中有平坡

5. 也可以用动态规划进行求解。

 1 class Solution:
 2     def wiggleMaxLength(self, nums):
 3         if len(nums) <= 1:
 4             return len(nums)  # 如果数组长度为0或1,则返回数组长度
 5         curDiff = 0  # 当前一对元素的差值
 6         preDiff = 0  # 前一对元素的差值
 7         result = 1  # 记录峰值的个数,初始为1(默认最右边的元素被视为峰值)
 8         for i in range(len(nums) - 1):
 9             curDiff = nums[i + 1] - nums[i]  # 计算下一个元素与当前元素的差值
10             # 如果遇到一个峰值
11             if (preDiff <= 0 and curDiff > 0) or (preDiff >= 0 and curDiff < 0):
12                 result += 1  # 峰值个数加1
13                 preDiff = curDiff  # 注意这里,只在摆动变化的时候更新preDiff
14         return result  # 返回最长摆动子序列的长度

 53. 最大子数组和

局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。

全局最优:选取最大“连续和”。

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

也可以用动态规划进行求解。

 1 class Solution:
 2     def maxSubArray(self, nums):
 3         result = float('-inf')  # 初始化结果为负无穷大
 4         count = 0
 5         for i in range(len(nums)):
 6             count += nums[i]
 7             if count > result:  # 取区间累计的最大值(相当于不断确定最大子序终止位置)
 8                 result = count
 9             if count <= 0:  # 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
10                 count = 0
11         return result

 122. 买卖股票的最佳时机 II

1. 其实最终利润是可以分解的。想获得利润至少要两天为一个交易单元。

2. 假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。
3. 收集每天的正利润就可以,收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润,不需要记录区间。
4. 局部最优:收集每天的正利润,全局最优:求得最大利润。
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
1 class Solution:
2     def maxProfit(self, prices: List[int]) -> int:
3         result = 0
4         for i in range(1, len(prices)):
5             result += max(prices[i] - prices[i - 1], 0)
6         return result

 

posted on 2023-09-16 10:25  小吴要努力  阅读(6)  评论(0编辑  收藏  举报