Skip to content

Commit 20fb449

Browse files
committed
update content
1 parent 7181751 commit 20fb449

File tree

74 files changed

+617
-715
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+617
-715
lines changed

README.md

+40-39
Large diffs are not rendered by default.

动态规划系列/LCS.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
88
</p>
99

10-
![](https://labuladong.github.io/pictures/souyisou1.png)
10+
![](https://labuladong.online/algo/images/souyisou1.png)
1111

1212
**通知:[新版网站会员](https://labuladong.online/algo/intro/site-vip/) 限时优惠;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo/intro/visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
1313

@@ -83,4 +83,4 @@ int longestCommonSubsequence(String s1, String s2);
8383

8484
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.online/algo/fname.html?fname=LCS) 查看:
8585

86-
![](https://labuladong.github.io/pictures/qrcode.jpg)
86+
![](https://labuladong.online/algo/images/qrcode.jpg)

动态规划系列/动态规划之KMP字符匹配算法.md

+26-26
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
88
</p>
99

10-
![](https://labuladong.github.io/pictures/souyisou1.png)
10+
![](https://labuladong.online/algo/images/souyisou1.png)
1111

1212
**通知:[新版网站会员](https://labuladong.online/algo/intro/site-vip/) 限时优惠;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo/intro/visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
1313

@@ -73,17 +73,17 @@ int search(String pat, String txt) {
7373

7474
比如 `txt = "aaacaaab", pat = "aaab"`
7575

76-
![](https://labuladong.github.io/pictures/kmp/1.gif)
76+
![](https://labuladong.online/algo/images/kmp/1.gif)
7777

7878
很明显,`pat` 中根本没有字符 c,根本没必要回退指针 `i`,暴力解法明显多做了很多不必要的操作。
7979

8080
KMP 算法的不同之处在于,它会花费空间来记录一些信息,在上述情况中就会显得很聪明:
8181

82-
![](https://labuladong.github.io/pictures/kmp/2.gif)
82+
![](https://labuladong.online/algo/images/kmp/2.gif)
8383

8484
再比如类似的 `txt = "aaaaaaab", pat = "aaab"`,暴力解法还会和上面那个例子一样蠢蠢地回退指针 `i`,而 KMP 算法又会耍聪明:
8585

86-
![](https://labuladong.github.io/pictures/kmp/3.gif)
86+
![](https://labuladong.online/algo/images/kmp/3.gif)
8787

8888
因为 KMP 算法知道字符 b 之前的字符 a 都是匹配的,所以每次只需要比较字符 b 是否被匹配就行了。
8989

@@ -106,11 +106,11 @@ pat = "aaab"
106106

107107
只不过对于 `txt1` 的下面这个即将出现的未匹配情况:
108108

109-
![](https://labuladong.github.io/pictures/kmp/txt1.jpg)
109+
![](https://labuladong.online/algo/images/kmp/txt1.jpg)
110110

111111
`dp` 数组指示 `pat` 这样移动:
112112

113-
![](https://labuladong.github.io/pictures/kmp/txt2.jpg)
113+
![](https://labuladong.online/algo/images/kmp/txt2.jpg)
114114

115115
::: note
116116

@@ -120,11 +120,11 @@ pat = "aaab"
120120

121121
而对于 `txt2` 的下面这个即将出现的未匹配情况:
122122

123-
![](https://labuladong.github.io/pictures/kmp/txt3.jpg)
123+
![](https://labuladong.online/algo/images/kmp/txt3.jpg)
124124

125125
`dp` 数组指示 `pat` 这样移动:
126126

127-
![](https://labuladong.github.io/pictures/kmp/txt4.jpg)
127+
![](https://labuladong.online/algo/images/kmp/txt4.jpg)
128128

129129
明白了 `dp` 数组只和 `pat` 有关,那么我们这样设计 KMP 算法就会比较漂亮:
130130

@@ -159,45 +159,45 @@ int pos2 = kmp.search("aaaaaaab"); //4
159159

160160
为什么说 KMP 算法和状态机有关呢?是这样的,我们可以认为 `pat` 的匹配就是状态的转移。比如当 pat = "ABABC":
161161

162-
![](https://labuladong.github.io/pictures/kmp/state.jpg)
162+
![](https://labuladong.online/algo/images/kmp/state.jpg)
163163

164164
如上图,圆圈内的数字就是状态,状态 0 是起始状态,状态 5(`pat.length`)是终止状态。开始匹配时 `pat` 处于起始状态,一旦转移到终止状态,就说明在 `txt` 中找到了 `pat`。比如说当前处于状态 2,就说明字符 "AB" 被匹配:
165165

166-
![](https://labuladong.github.io/pictures/kmp/state2.jpg)
166+
![](https://labuladong.online/algo/images/kmp/state2.jpg)
167167

168168
另外,处于不同状态时,`pat` 状态转移的行为也不同。比如说假设现在匹配到了状态 4,如果遇到字符 A 就应该转移到状态 3,遇到字符 C 就应该转移到状态 5,如果遇到字符 B 就应该转移到状态 0:
169169

170-
![](https://labuladong.github.io/pictures/kmp/state4.jpg)
170+
![](https://labuladong.online/algo/images/kmp/state4.jpg)
171171

172172
具体什么意思呢,我们来一个个举例看看。用变量 `j` 表示指向当前状态的指针,当前 `pat` 匹配到了状态 4:
173173

174-
![](https://labuladong.github.io/pictures/kmp/exp1.jpg)
174+
![](https://labuladong.online/algo/images/kmp/exp1.jpg)
175175

176176
如果遇到了字符 "A",根据箭头指示,转移到状态 3 是最聪明的:
177177

178-
![](https://labuladong.github.io/pictures/kmp/exp3.jpg)
178+
![](https://labuladong.online/algo/images/kmp/exp3.jpg)
179179

180180
如果遇到了字符 "B",根据箭头指示,只能转移到状态 0(一夜回到解放前):
181181

182-
![](https://labuladong.github.io/pictures/kmp/exp5.jpg)
182+
![](https://labuladong.online/algo/images/kmp/exp5.jpg)
183183

184184
如果遇到了字符 "C",根据箭头指示,应该转移到终止状态 5,这也就意味着匹配完成:
185185

186-
![](https://labuladong.github.io/pictures/kmp/exp7.jpg)
186+
![](https://labuladong.online/algo/images/kmp/exp7.jpg)
187187

188188
当然了,还可能遇到其他字符,比如 Z,但是显然应该转移到起始状态 0,因为 `pat` 中根本都没有字符 Z:
189189

190-
![](https://labuladong.github.io/pictures/kmp/z.jpg)
190+
![](https://labuladong.online/algo/images/kmp/z.jpg)
191191

192192
这里为了清晰起见,我们画状态图时就把其他字符转移到状态 0 的箭头省略,只画 `pat` 中出现的字符的状态转移:
193193

194-
![](https://labuladong.github.io/pictures/kmp/allstate.jpg)
194+
![](https://labuladong.online/algo/images/kmp/allstate.jpg)
195195

196196
KMP 算法最关键的步骤就是构造这个状态转移图。**要确定状态转移的行为,得明确两个变量,一个是当前的匹配状态,另一个是遇到的字符**;确定了这两个变量后,就可以知道这个情况下应该转移到哪个状态。
197197

198198
下面看一下 KMP 算法根据这幅状态转移图匹配字符串 `txt` 的过程:
199199

200-
![](https://labuladong.github.io/pictures/kmp/kmp.gif)
200+
![](https://labuladong.online/algo/images/kmp/kmp.gif)
201201

202202
**请记住这个 GIF 的匹配过程,这就是 KMP 算法的核心逻辑**
203203

@@ -253,29 +253,29 @@ for 0 <= j < M: # 状态
253253

254254
这个 next 状态应该怎么求呢?显然,**如果遇到的字符 `c``pat[j]` 匹配的话**,状态就应该向前推进一个,也就是说 `next = j + 1`,我们不妨称这种情况为**状态推进**
255255

256-
![](https://labuladong.github.io/pictures/kmp/forward.jpg)
256+
![](https://labuladong.online/algo/images/kmp/forward.jpg)
257257

258258
**如果字符 `c``pat[j]` 不匹配的话**,状态就要回退(或者原地不动),我们不妨称这种情况为**状态重启**
259259

260-
![](https://labuladong.github.io/pictures/kmp/back.jpg)
260+
![](https://labuladong.online/algo/images/kmp/back.jpg)
261261

262262
那么,如何得知在哪个状态重启呢?解答这个问题之前,我们再定义一个名字:**影子状态**(我编的名字),用变量 `X` 表示。**所谓影子状态,就是和当前状态具有相同的前缀**。比如下面这种情况:
263263

264-
![](https://labuladong.github.io/pictures/kmp/shadow.jpg)
264+
![](https://labuladong.online/algo/images/kmp/shadow.jpg)
265265

266266
当前状态 `j = 4`,其影子状态为 `X = 2`,它们都有相同的前缀 "AB"。因为状态 `X` 和状态 `j` 存在相同的前缀,所以当状态 `j` 准备进行状态重启的时候(遇到的字符 `c``pat[j]` 不匹配),可以通过 `X` 的状态转移图来获得**最近的重启位置**
267267

268268
比如说刚才的情况,如果状态 `j` 遇到一个字符 "A",应该转移到哪里呢?首先只有遇到 "C" 才能推进状态,遇到 "A" 显然只能进行状态重启。**状态 `j` 会把这个字符委托给状态 `X` 处理,也就是 `dp[j]['A'] = dp[X]['A']`**
269269

270-
![](https://labuladong.github.io/pictures/kmp/shadow1.jpg)
270+
![](https://labuladong.online/algo/images/kmp/shadow1.jpg)
271271

272272
为什么这样可以呢?因为:既然 `j` 这边已经确定字符 "A" 无法推进状态,**只能回退**,而且 KMP 就是要**尽可能少的回退**,以免多余的计算。那么 `j` 就可以去问问和自己具有相同前缀的 `X`,如果 `X` 遇见 "A" 可以进行「状态推进」,那就转移过去,因为这样回退最少。
273273

274-
![](https://labuladong.github.io/pictures/kmp/A.gif)
274+
![](https://labuladong.online/algo/images/kmp/A.gif)
275275

276276
当然,如果遇到的字符是 "B",状态 `X` 也不能进行「状态推进」,只能回退,`j` 只要跟着 `X` 指引的方向回退就行了:
277277

278-
![](https://labuladong.github.io/pictures/kmp/shadow2.jpg)
278+
![](https://labuladong.online/algo/images/kmp/shadow2.jpg)
279279

280280
你也许会问,这个 `X` 怎么知道遇到字符 "B" 要回退到状态 0 呢?因为 `X` 永远跟在 `j` 的身后,状态 `X` 如何转移,在之前就已经算出来了。动态规划算法不就是利用过去的结果解决现在的问题吗?
281281

@@ -370,7 +370,7 @@ for (int i = 0; i < N; i++) {
370370

371371
下面来看一下状态转移图的完整构造过程,你就能理解状态 `X` 作用之精妙了:
372372

373-
![](https://labuladong.github.io/pictures/kmp/dfa.gif)
373+
![](https://labuladong.online/algo/images/kmp/dfa.gif)
374374

375375
至此,KMP 算法的核心终于写完啦啦啦啦!看下 KMP 算法的完整代码吧:
376376

@@ -457,7 +457,7 @@ KMP 算法也就是动态规划那点事,我们的公众号文章目录有一
457457

458458
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
459459

460-
![](https://labuladong.github.io/pictures/souyisou2.png)
460+
![](https://labuladong.online/algo/images/souyisou2.png)
461461

462462
======其他语言代码======
463463

动态规划系列/动态规划之博弈问题.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
88
</p>
99

10-
![](https://labuladong.github.io/pictures/souyisou1.png)
10+
![](https://labuladong.online/algo/images/souyisou1.png)
1111

1212
**通知:[新版网站会员](https://labuladong.online/algo/intro/site-vip/) 限时优惠;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo/intro/visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
1313

@@ -65,7 +65,7 @@ public boolean PredictTheWinner(int[] nums) {
6565

6666
介绍 `dp` 数组的含义之前,我们先看一下 `dp` 数组最终的样子:
6767

68-
![](https://labuladong.github.io/pictures/博弈问题/1.png)
68+
![](https://labuladong.online/algo/images/博弈问题/1.png)
6969

7070
下文讲解时,认为元组是包含 `first``second` 属性的一个类,而且为了节省篇幅,将这两个属性简写为 `fir``sec`。比如按上图的数据,我们说 `dp[1][3].fir = 11``dp[0][1].sec = 2`
7171

@@ -147,11 +147,11 @@ dp[i][j].sec = 0
147147
# 后手没有石头拿了,得分为 0
148148
```
149149

150-
![](https://labuladong.github.io/pictures/博弈问题/2.png)
150+
![](https://labuladong.online/algo/images/博弈问题/2.png)
151151

152152
这里需要注意一点,我们发现 base case 是斜着的,而且我们推算 `dp[i][j]` 时需要用到 `dp[i+1][j]``dp[i][j-1]`
153153

154-
![](https://labuladong.github.io/pictures/博弈问题/3.png)
154+
![](https://labuladong.online/algo/images/博弈问题/3.png)
155155

156156
根据前文 [动态规划答疑篇](https://labuladong.online/algo/fname.html?fname=最优子结构) 判断 `dp` 数组遍历方向的原则,算法应该倒着遍历 `dp` 数组:
157157

@@ -163,7 +163,7 @@ for (int i = n - 2; i >= 0; i--) {
163163
}
164164
```
165165

166-
![](https://labuladong.github.io/pictures/博弈问题/4.png)
166+
![](https://labuladong.online/algo/images/博弈问题/4.png)
167167

168168
### 三、代码实现
169169

@@ -250,7 +250,7 @@ int stoneGame(int[] piles) {
250250

251251
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
252252

253-
![](https://labuladong.github.io/pictures/souyisou2.png)
253+
![](https://labuladong.online/algo/images/souyisou2.png)
254254

255255
======其他语言代码======
256256

动态规划系列/动态规划之四键键盘.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
88
</p>
99

10-
![](https://labuladong.github.io/pictures/souyisou1.png)
10+
![](https://labuladong.online/algo/images/souyisou1.png)
1111

1212
**通知:[新版网站会员](https://labuladong.online/algo/intro/site-vip/) 限时优惠;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo/intro/visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
1313

@@ -194,7 +194,7 @@ public int maxA(int N) {
194194

195195
其中 `j` 变量减 2 是给 `C-A C-C` 留下操作数,看个图就明白了:
196196

197-
![](https://labuladong.github.io/pictures/4keyboard/1.jpg)
197+
![](https://labuladong.online/algo/images/4keyboard/1.jpg)
198198

199199
这样,此算法就完成了,时间复杂度 O(N^2),空间复杂度 O(N),这种解法应该是比较高效的了。
200200

@@ -236,7 +236,7 @@ def dp(n, a_num, copy):
236236

237237
**《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**
238238

239-
![](https://labuladong.github.io/pictures/souyisou2.png)
239+
![](https://labuladong.online/algo/images/souyisou2.png)
240240

241241
======其他语言代码======
242242

动态规划系列/动态规划之正则表达.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<a href="https://space.bilibili.com/14089380"><img src="https://img.shields.io/badge/B站-@labuladong-000000.svg?style=flat-square&logo=Bilibili"></a>
88
</p>
99

10-
![](https://labuladong.github.io/pictures/souyisou1.png)
10+
![](https://labuladong.online/algo/images/souyisou1.png)
1111

1212
**通知:[新版网站会员](https://labuladong.online/algo/intro/site-vip/) 限时优惠;算法可视化编辑器上线,[点击体验](https://labuladong.online/algo/intro/visualize/)!另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。**
1313

@@ -148,7 +148,7 @@ bool dp(string& s, int i, string& p, int j);
148148
149149
本文为会员内容,请扫码关注公众号或 [点这里](https://labuladong.online/algo/fname.html?fname=动态规划之正则表达) 查看:
150150
151-
![](https://labuladong.github.io/pictures/qrcode.jpg)
151+
![](https://labuladong.online/algo/images/qrcode.jpg)
152152
153153
======其他语言代码======
154154

0 commit comments

Comments
 (0)