leetcode/notes/src/greedy.md

5.9 KiB

总结

使用场景:手动模拟一下感觉可以局部最优推出整体最优,而且想不到反例,那么就试一试贪心。

思路:

假设题干是这样的:给出一系列元素(通常放在一个数组中),请你从中挑选出满足条件的 N 个数,使得总和最大。

来分析一下题干:

  • 一系列元素,这是 base
  • 满足条件的 N 个数,这是限制条件
  • 总和最大,这是全局最优的优化目标

贪心算法是怎样的呢?就是直接找全局最优一般不好找,我们可以在 base 上找局部最优,比如我们可以这么设计:

  • 总和大于 0 的一段连续子数组,这是限制条件
  • 长度最长,这是局部最优的优化目标

限制条件和优化目标都不一定要和全局最优一样,但是这里有个关键:

你在找局部最优的过程中可以推导出全局最优。

注意,不是从所有局部最优的结果中推导出全局最优的结果,而是你在寻找局部最优的过程中可以找到全局最优。

什么意思?

假设你找到了 K 个局部最优结果,但我们并不是要从这 K 个结果中推出全局最优,而是在你找这 K 个结果的过程中,我们可以用一个变量 record 来记录某些东西,然后由这个变量 record 和这 K 个局部最优结果共同推导出全局最优解。


53. 最大子序和

Given an integer array nums, find the subarray with the largest sum, and return its sum.

Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: The subarray [4,-1,2,1] has the largest sum 6.

全局:

  • 限制:连续子数组
  • 目标:总和最大

局部:

  • 限制:连续子数组,总和大于零
  • 目标:该子数组长度最长

过程:

在找最长子数组时用一个变量 count 记录当前总和,用一个变量 max 记录最大总和。

  • if (count > max) max = count
  • if (count < 0) count = 0

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

You are given an integer array prices where prices[i] is the price of a given stock on the ith day.

On each day, you may decide to buy and/or sell the stock. You can only hold at most one share of the stock at any time. However, you can buy it then immediately sell it on the same day.

Find and return the maximum profit you can achieve.

Input: prices = [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Total profit is 4 + 3 = 7.

全局目标:总利润最大

局部目标:最长上升区间

过程:找到每个最长上升区间,将每个上升区间的利润加起来就是总利润了。

55. 跳跃游戏

You are given an integer array nums. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position.

Return true if you can reach the last index, or false otherwise.

Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

全局最优:找到最长覆盖距离

局部最优:找到当前区间的最长覆盖距离

过程:一开始第一个元素的值就是初始覆盖区间的长度,遍历这个区间的所有元素,看看能不能找到能延长当前区间覆盖距离的元素,并延长区间覆盖距离,这样一直迭代,看它能不能到达数组末尾。

45. 跳跃游戏 II

You are given a 0-indexed array of integers nums of length n. You are initially positioned at nums[0].

Each element nums[i] represents the maximum length of a forward jump from index i. In other words, if you are at nums[i], you can jump to any nums[i + j] where:

  • 0 <= j <= nums[i] and
  • i + j < n

Return the minimum number of jumps to reach nums[n - 1]. The test cases are generated such that you can reach nums[n - 1].

全局最优:找到最短步数达到最长覆盖距离

局部最优:找到当前覆盖区间的元素,使得能最大程度地延长当前覆盖范围。

过程:一开始第一个元素的值就是初始覆盖区间的长度,遍历这个区间的所有元素,找到这样一个元素,它能够最大程度地延长当前覆盖区间,这个元素就是下一跳。在下一个覆盖区间中,再找到同样的元素,这样一直迭代。

452. 用最少数量的箭引爆气球

全局:

  • 限制:射完全部气球
  • 目标:消耗的箭的数量最少

局部:

  • 限制:射箭的范围是当前气球所在的范围
  • 目标:这一箭要射穿的气球数量达到最大

算法优化:先对左边界(或右边界)进行排序,以降低时间复杂度。

435. 无重叠区间

从左向右记录非交叉区间的个数,用区间总数减去非交叉区间的个数就是需要移除的区间个数了。问题就是要求非交叉区间的最大个数。

先按右边界进行排序。

局部最优:优先选右边界小的区间,所以从左向右遍历,留给下一个区间的空间大一些,从而尽量避免交叉。

全局最优:选取最多的非交叉区间。

56. 合并区间

先按左边界排序。

局部最优:当前区间能合并出的最长区间

全局最优:合并所有重叠区间

968. 监控二叉树

局部最优:让叶子节点的父节点安摄像头,所用摄像头最少

全局最优:全部摄像头数量所用最少