Skip to content

Commit 11e5ba0

Browse files
committed
Update 01.Greedy-Algorithm.md
1 parent e9c7925 commit 11e5ba0

File tree

1 file changed

+59
-17
lines changed

1 file changed

+59
-17
lines changed

Contents/09.Algorithm-Base/05.Greedy-Algorithm/01.Greedy-Algorithm.md

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@
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

@@ -26,9 +31,11 @@
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

@@ -40,10 +47,11 @@
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

@@ -82,14 +90,26 @@
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` 进行排序,并且对于每个孩子,应该选择满足这个孩子的胃口且尺寸最小的饼干。
@@ -108,7 +128,7 @@
108128
2. 如果 `g[index_g] > s[index_s]`,说明当前饼干无法满足当前孩子胃口,则向右移动 `index_s`,判断下一块饼干是否可以满足当前孩子胃口。
109129
3. 遍历完输出答案 `res`
110130

111-
#### 4.1.4 代码
131+
##### 思路 1:代码
112132

113133
```Python
114134
class 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` 更新为新区间的结束位置。
174211
3. 最终返回「总区间个数 - 不重叠区间的最多个数」即 `len(intervals) - count` 作为答案。
175212

176-
#### 4.2.4 代码
213+
##### 思路 1:代码
177214

178215
```Python
179216
class 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

Comments
 (0)