88
99换句话说,贪心算法不从整体最优上加以考虑,而是一步一步进行,每一步只以当前情况为基础,根据某个优化测度做出局部最优选择,从而省去了为找到最优解要穷举所有可能所必须耗费的大量时间。
1010
11- 当然,使用贪心算法所得到的最终解并不一定就是全局最优解。但是对许多问题来说,确实可以通过局部最优解而得到整体最优解或者是整体最优解的近似解 。
11+ 对许多问题来说,可以使用贪心算法,通过局部最优解而得到整体最优解或者是整体最优解的近似解 。
1212
13- 一般来说,这些能够使用贪心算法解决的问题必须满足下面的两个特征:「贪⼼选择性质」和「最优子结构」。
13+ 但并不是所有问题,都可以使用贪心算法的。
14+
15+ 一般来说,这些能够使用贪心算法解决的问题必须满足下面的两个特征:
16+
17+ 1 . ** 贪⼼选择性质**
18+ 2 . ** 最优子结构**
1419
1520### 1.2 贪心算法的特征
1621
1722#### 1.2.1 贪心选择性质
1823
19- 「 贪心选择」 :指的是一个问题的全局最优解可以通过一系列局部最优解(贪心选择)来得到。
24+ > ** 贪心选择** :指的是一个问题的全局最优解可以通过一系列局部最优解(贪心选择)来得到。
2025
2126换句话说,当进行选择时,我们直接做出在当前问题中看来最优的选择,而不用去考虑子问题的解。在做出选择之后,才会去求解剩下的子问题,如下图所示。
2227
2631
2732#### 1.2.2 最优子结构性质
2833
29- 「最优子结构」:指的是一个问题的最优解包含其子问题的最优解。
34+ > ** 最优子结构** :指的是一个问题的最优解包含其子问题的最优解。
35+
36+ 问题的最优子结构性质是该问题能否用贪心算法求解的关键。
3037
31- 问题的最优子结构性质是该问题能否用贪心算法求解的关键。 举个例子,如下图所示,原问题 $S = \lbrace a_1, a_2, a_3, a_4 \rbrace$,在 $a_1$ 步我们通过贪心选择选出一个当前最优解之后,问题就转换为求解子问题 $S_ {子问题} = \lbrace a_2, a_3, a_4 \rbrace$。如果原问题 $S$ 的最优解可以由「第 $a_1$ 步通过贪心选择的局部最优解」和「 $S_ {子问题}$ 的最优解」构成,则说明该问题满足最优子结构性质。
38+ 举个例子,如下图所示,原问题 $S = \lbrace a_1, a_2, a_3, a_4 \rbrace$,在 $a_1$ 步我们通过贪心选择选出一个当前最优解之后,问题就转换为求解子问题 $S_ {子问题} = \lbrace a_2, a_3, a_4 \rbrace$。如果原问题 $S$ 的最优解可以由「第 $a_1$ 步通过贪心选择的局部最优解」和「 $S_ {子问题}$ 的最优解」构成,则说明该问题满足最优子结构性质。
3239
3340也就是说,如果原问题的最优解包含子问题的最优解,则说明该问题满足最优子结构性质。
3441
4047
4148### 1.3 贪心算法正确性的证明
4249
43- 贪心算法最难的部分不在于问题的求解,而在于是正确性的证明。常用的证明方法有 「数学归纳法」和「交换论证法」。
50+ 贪心算法最难的部分不在于问题的求解,而在于是正确性的证明。我们常用的证明方法有 「数学归纳法」和「交换论证法」。
4451
45- - ** 数学归纳法** :先计算出边界情况(例如 $n = 1$)的最优解,然后再证明对于每个 $n$,$F_ {n + 1}$ 都可以由 $F_n$ 推导出。
46- - ** 交换论证法** :从最优解出发,在保证全局最优不变的前提下,如果交换方案中任意两个元素 / 相邻的两个元素后,答案不会变得更好,则可以推定目前的解是最优解。
52+ > - ** 数学归纳法** :先计算出边界情况(例如 $n = 1$)的最优解,然后再证明对于每个 $n$,$F_ {n + 1}$ 都可以由 $F_n$ 推导出。
53+ >
54+ > - ** 交换论证法** :从最优解出发,在保证全局最优不变的前提下,如果交换方案中任意两个元素 / 相邻的两个元素后,答案不会变得更好,则可以推定目前的解是最优解。
4755
4856判断一个问题是否通过贪心算法求解,是需要进行严格的数学证明的。但是在日常写题或者算法面试中,不太会要求大家去证明贪心算法的正确性。
4957
8290
8391** 示例** :
8492
93+ - 示例 1:
94+
95+ ``` Python
96+ 输入:g = [1 ,2 ,3 ], s = [1 ,1 ]
97+ 输出:1
98+ 解释:你有三个孩子和两块小饼干,3 个孩子的胃口值分别是:1 , 2 , 3 。虽然你有两块小饼干,由于他们的尺寸都是 1 ,你只能让胃口值是 1 的孩子满足。所以应该输出 1 。
99+ ```
100+
101+ - 示例 2:
102+
85103``` Python
86- 输入 g = [1 ,2 , 3 ], s = [1 ,1 ]
87- 输出 1
88- 解释 你有三个孩子和两块小饼干, 3 个孩子的胃口值分别是: 1 , 2 , 3 。虽然你有两块小饼干,由于他们的尺寸都是 1 ,你只能让胃口值是 1 的孩子满足。所以应该输出 1 。
104+ 输入: g = [1 ,2 ], s = [1 ,2 , 3 ]
105+ 输出: 2
106+ 解释: 你有两个孩子和三块小饼干, 2 个孩子的胃口值分别是 1 , 2 。你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出 2 。
89107```
90108
91109#### 4.1.3 解题思路
92110
111+ ##### 思路 1:贪心算法
112+
93113为了尽可能的满⾜更多的⼩孩,而且一块饼干不能掰成两半,所以我们应该尽量让胃口小的孩子吃小块饼干,这样胃口大的孩子才有大块饼干吃。
94114
95115所以,从贪心算法的角度来考虑,我们应该按照孩子的胃口从小到大对数组 ` g ` 进行排序,然后按照饼干的尺寸大小从小到大对数组 ` s ` 进行排序,并且对于每个孩子,应该选择满足这个孩子的胃口且尺寸最小的饼干。
108128 2 . 如果 ` g[index_g] > s[index_s] ` ,说明当前饼干无法满足当前孩子胃口,则向右移动 ` index_s ` ,判断下一块饼干是否可以满足当前孩子胃口。
1091293 . 遍历完输出答案 ` res ` 。
110130
111- #### 4.1.4 代码
131+ ##### 思路 1: 代码
112132
113133``` Python
114134class Solution :
@@ -128,6 +148,11 @@ class Solution:
128148 return res
129149```
130150
151+ ##### 思路 1:复杂度分析
152+
153+ - ** 时间复杂度** :$O(m \times \log m + n \times \log n)$,其中 $m$ 和 $n$ 分别是数组 $g$ 和 $s$ 的长度。
154+ - ** 空间复杂度** :$O(\log m + \log n)$。
155+
131156### 4.2 无重叠区间
132157
133158#### 4.2.1 题目链接
@@ -148,15 +173,27 @@ class Solution:
148173
149174** 示例** :
150175
176+ - 示例 1:
177+
151178``` Python
152- 输入 intervals = [[1 ,2 ],[2 ,3 ],[3 ,4 ],[1 ,3 ]]
153- 输出 1
154- 解释 移除 [1 ,3 ] 后,剩下的区间没有重叠。
179+ 输入:intervals = [[1 ,2 ],[2 ,3 ],[3 ,4 ],[1 ,3 ]]
180+ 输出:1
181+ 解释:移除 [1 ,3 ] 后,剩下的区间没有重叠。
182+ ```
183+
184+ - 示例 2:
185+
186+ ``` Python
187+ 输入: intervals = [ [1 ,2 ], [1 ,2 ], [1 ,2 ] ]
188+ 输出: 2
189+ 解释: 你需要移除两个 [1 ,2 ] 来使剩下的区间没有重叠。
155190```
156191
157192#### 4.2.3 解题思路
158193
159- 这道题我们可以转换一下思路。原题要求保证移除区间最少,使得剩下的区间互不重叠。换个角度就是:「如何使得剩下互补重叠区间的数目最多」。那么答案就变为了:「总区间个数 - 不重叠区间的最多个数」。我们的问题也变成了求所有区间中不重叠区间的最多个数。
194+ ##### 思路 1:贪心算法
195+
196+ 这道题我们可以转换一下思路。原题要求保证移除区间最少,使得剩下的区间互不重叠。换个角度就是:「如何使得剩下互不重叠区间的数目最多」。那么答案就变为了:「总区间个数 - 不重叠区间的最多个数」。我们的问题也变成了求所有区间中不重叠区间的最多个数。
160197
161198从贪心算法的角度来考虑,我们应该将区间按照结束时间排序。每次选择结束时间最早的区间,然后再在剩下的时间内选出最多的区间。
162199
@@ -173,7 +210,7 @@ class Solution:
173210 1 . 如果 ` end_pos <= intervals[i][0] ` ,即 ` end_pos ` 小于等于区间起始位置,则说明出现了不重叠区间,令不重叠区间数 ` count ` 加 ` 1 ` ,` end_pos ` 更新为新区间的结束位置。
1742113 . 最终返回「总区间个数 - 不重叠区间的最多个数」即 ` len(intervals) - count ` 作为答案。
175212
176- #### 4.2.4 代码
213+ ##### 思路 1: 代码
177214
178215``` Python
179216class Solution :
@@ -191,6 +228,11 @@ class Solution:
191228 return len (intervals) - count
192229```
193230
231+ ##### 思路 1:复杂度分析
232+
233+ - ** 时间复杂度** :$O(n \times \log n)$,其中 $n$ 是区间的数量。
234+ - ** 空间复杂度** :$O(\log n)$。
235+
194236## 参考资料
195237
196238- 【博文】[ 贪心 - OI Wiki] ( https://oi-wiki.org/basic/greedy/ )
0 commit comments