Skip to content

Commit b28bf5d

Browse files
committed
添加B站视频
2 parents 1e912c8 + 637f40d commit b28bf5d

Some content is hidden

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

58 files changed

+7008
-228
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ Gitee Pages 地址:https://labuladong.gitee.io/algo
181181
[PaperJets](https://github.com/PaperJets),
182182
[qy-yang](https://github.com/qy-yang),
183183
[realism0331](https://github.com/realism0331),
184-
[SCUhzs](https://github.com/HuangZiSheng001),
184+
[SCUhzs](https://github.com/brucecat),
185185
[Seaworth](https://github.com/Seaworth),
186186
[shazi4399](https://github.com/shazi4399),
187187
[ShuozheLi](https://github.com/ShuoZheLi/),
@@ -190,7 +190,7 @@ Gitee Pages 地址:https://labuladong.gitee.io/algo
190190
[Tianhao Zhou](https://github.com/tianhaoz95),
191191
[timmmGZ](https://github.com/timmmGZ),
192192
[tommytim0515](https://github.com/tommytim0515),
193-
[upbin](https://github.com/upbin),
193+
[ucsk](https://github.com/ucsk),
194194
[wadegrc](https://github.com/wadegrc),
195195
[walsvid](https://github.com/walsvid),
196196
[warmingkkk](https://github.com/warmingkkk),

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

+117-30
Original file line numberDiff line numberDiff line change
@@ -430,41 +430,128 @@ KMP 算法也就是动态规划那点事,我们的公众号文章目录有一
430430
<p align='center'>
431431
<img src="../pictures/qrcode.jpg" width=200 >
432432
</p>
433-
434433
======其他语言代码======
434+
435+
[28.实现 strStr()](https://leetcode-cn.com/problems/implement-strstr)
436+
437+
### python
438+
435439
[MoguCloud](https://github.com/MoguCloud) 提供 实现 strStr() 的 Python 完整代码:
436-
```py
440+
441+
```python
437442
class Solution:
438-
def strStr(self, haystack: str, needle: str) -> int:
439-
# 边界条件判断
440-
if not needle:
441-
return 0
442-
pat = needle
443-
txt = haystack
444-
445-
M = len(pat)
446-
# dp[状态][字符] = 下个状态
447-
dp = [[0 for _ in range(256)] for _ in pat]
448-
# base case
449-
dp[0][ord(pat[0])] = 1
450-
# 影子状态 X 初始化为 0
451-
X = 0
452-
for j in range(1, M):
453-
for c in range(256):
454-
dp[j][c] = dp[X][c]
455-
dp[j][ord(pat[j])] = j + 1
456-
# 更新影子状态
457-
X = dp[X][ord(pat[j])]
458-
443+
def strStr(self, haystack: str, needle: str) -> int:
444+
# 边界条件判断
445+
if not needle:
446+
return 0
447+
pat = needle
448+
txt = haystack
449+
450+
M = len(pat)
451+
# dp[状态][字符] = 下个状态
452+
dp = [[0 for _ in range(256)] for _ in pat]
453+
# base case
454+
dp[0][ord(pat[0])] = 1
455+
# 影子状态 X 初始化为 0
456+
X = 0
457+
for j in range(1, M):
458+
for c in range(256):
459+
dp[j][c] = dp[X][c]
460+
dp[j][ord(pat[j])] = j + 1
461+
# 更新影子状态
462+
X = dp[X][ord(pat[j])]
463+
459464
N = len(txt)
460465
# pat 初始状态为 0
461466
j = 0
462467
for i in range(N):
463-
# 计算 pat 的下一个状态
464-
j = dp[j][ord(txt[i])]
465-
# 到达终止态,返回结果
466-
if j == M:
467-
return i - M + 1
468-
# 没到达终止态,匹配失败
469-
return -1
468+
# 计算 pat 的下一个状态
469+
j = dp[j][ord(txt[i])]
470+
# 到达终止态,返回结果
471+
if j == M:
472+
return i - M + 1
473+
# 没到达终止态,匹配失败
474+
return -1
470475
```
476+
477+
478+
479+
### javascript
480+
481+
```js
482+
class KMP {
483+
constructor(pat) {
484+
this.pat = pat;
485+
let m = pat.length;
486+
487+
// dp[状态][字符] = 下个状态 初始化一个m*256的整数矩阵
488+
this.dp = new Array(m);
489+
for (let i = 0; i < m; i++) {
490+
this.dp[i] = new Array(256);
491+
this.dp[i].fill(0, 0, 256);
492+
}
493+
494+
// base case
495+
this.dp[0][this.pat[0].charCodeAt()] = 1;
496+
497+
// 影子状态X 初始为0
498+
let x = 0;
499+
500+
// 构建状态转移图
501+
for (let j = 1; j < m; j++) {
502+
for (let c = 0; c < 256; c++) {
503+
this.dp[j][c] = this.dp[x][c];
504+
}
505+
506+
// dp[][对应的ASCII码]
507+
this.dp[j][this.pat[j].charCodeAt()] = j + 1;
508+
509+
// 更新影子状态
510+
x = this.dp[x][this.pat[j].charCodeAt()]
511+
}
512+
}
513+
514+
search(txt) {
515+
516+
let m = this.pat.length;
517+
let n = txt.length;
518+
519+
// pat的初始态为0
520+
let j = 0;
521+
for (let i = 0; i < n; i++) {
522+
// 计算pat的下一个状态
523+
j = this.dp[j][txt[i].charCodeAt()];
524+
525+
// 到达终止态 返回结果
526+
if (j === m) return i - m + 1;
527+
}
528+
529+
// 没到终止态 匹配失败
530+
return -1;
531+
}
532+
533+
}
534+
535+
/**
536+
* @param {string} haystack
537+
* @param {string} needle
538+
* @return {number}
539+
*/
540+
var strStr = function(haystack, needle) {
541+
if(haystack === ""){
542+
if(needle !== ""){
543+
return -1;
544+
}
545+
return 0;
546+
}
547+
548+
if(needle === ""){
549+
return 0;
550+
}
551+
let kmp = new KMP(needle);
552+
return kmp.search(haystack)
553+
};
554+
```
555+
556+
557+

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

+113-7
Original file line numberDiff line numberDiff line change
@@ -214,14 +214,9 @@ int stoneGame(int[] piles) {
214214
<p align='center'>
215215
<img src="../pictures/qrcode.jpg" width=200 >
216216
</p>
217-
218217
======其他语言代码======
219218

220-
221-
222-
223-
224-
* python3版本
219+
### python
225220

226221
由[SCUHZS](https://github.com/brucecat)提供
227222

@@ -287,7 +282,9 @@ class Solution:
287282

288283
```
289284

290-
* C++ 版本
285+
286+
287+
### C++ 版本
291288

292289
由 [TCeason](https://github.com/TCeason) 提供
293290

@@ -328,3 +325,112 @@ public:
328325

329326
```
330327

328+
329+
330+
### javascript
331+
332+
由[SCUHZS](https://github.com/brucecat)提供
333+
334+
**1、暴力递归解**
335+
336+
```js
337+
/**
338+
* 返回[i,j]上先手所能取得的最优决策的值
339+
* @param piles
340+
* @param i
341+
* @param j
342+
* @return {number|*}
343+
*/
344+
var f=function(piles,i,j) {
345+
if(i===j){ //如果i===j,只有一个元素,那么先手只能选它
346+
return piles[i]
347+
}
348+
//否则 有2种情况:
349+
//1 先选i,之后在[i+1,j]上后手进行最优选择
350+
//2 先选j,之后在[i,j-1]上后手进行最优选择
351+
return Math.max(piles[i]+s(i+1,j),piles[j]+s(i,j-1))
352+
}
353+
/**
354+
*返回[i,j]上后手所能取得的最优决策的值
355+
* @param piles
356+
* @param i
357+
* @param j
358+
* @return {number}
359+
*/
360+
var s=function(piles,i,j) {
361+
if(i===j){ //如果i===j,只有一个元素,那么后手没有选,只能为0
362+
return 0
363+
}
364+
//对于这种双方都是绝顶聪明的人,数据一开始对于双方都是可见的,那么数据一确定,先后手一确定,那么结果就已经确定了
365+
//先手选的人会把最优解选了,那么剩给后手的只有最差的情况
366+
//所以后手的人虽然能从剩下的之中进行最优决策,但结果确是命中注定的了,只能是最差的
367+
//所以返回[i+1,j] [i,j-1]上进行最优选择的最小值
368+
//这也说明了先手的人在大概率下会赢得游戏(在某些情况下先手必赢,比如本题的情况:具体分析看官方解析)
369+
return Math.min(f(i+1,j),f(i,j-1))
370+
}
371+
/**
372+
*
373+
* @param piles
374+
* @return {boolean}
375+
*/
376+
var stoneGame = function(piles) {
377+
return f(0,piles.length-1)>s(0,piles.length-1) //亚历克斯先选和李后选得到的最大值做比较
378+
};
379+
```
380+
381+
**2、动态规划dp做法**
382+
383+
这里采取的是三维的做法
384+
385+
```js
386+
var stoneGame = function (piles) {
387+
let n = piles.length;
388+
389+
// 初始化一个n*n的矩阵 dp数组
390+
let dp = []
391+
for (let i = 0; i < n; i++) {
392+
dp[i] = []
393+
}
394+
395+
// 在三角区域填充
396+
for (let i = 0; i < n; i++) {
397+
for (let j = i; j < n; j++) {
398+
dp[i][j] = [0, 0]
399+
}
400+
}
401+
402+
403+
// 填入base case
404+
for (let i = 0; i < n; i++) {
405+
dp[i][i][0] = piles[i];
406+
dp[i][i][1] = 0;
407+
}
408+
409+
// 斜着遍历数组
410+
for (let l = 2; l <= n; l++) {
411+
for (let i = 0; i <= n - 1; i++) {
412+
let j = l + i - 1;
413+
414+
// 先手选择最左边或最右边的分数
415+
let left = piles[i] + dp[i + 1][j][1];
416+
let right = piles[j] + dp[i][j - 1][1];
417+
418+
// 套用状态转移方程
419+
if (left > right) {
420+
dp[i][j][0] = left;
421+
dp[i][j][1] = dp[i + 1][j][0];
422+
} else {
423+
dp[i][j][0] = right;
424+
dp[i][j][1] = dp[i][j - 1][0];
425+
}
426+
}
427+
}
428+
429+
let res = dp[0][n - 1];
430+
return res[0] - res[1]
431+
};
432+
```
433+
434+
435+
436+
###

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

+58-2
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ dp[i] = dp[i - 1] + 1;
146146
但是,如果要按 `C-V`,还要考虑之前是在哪里 `C-A C-C` 的。
147147

148148
**刚才说了,最优的操作序列一定是 `C-A C-C` 接着若干 `C-V`,所以我们用一个变量 `j` 作为若干 `C-V` 的起点**。那么 `j` 之前的 2 个操作就应该是 `C-A C-C` 了:
149-
149+
150150
```java
151151
public int maxA(int N) {
152152
int[] dp = new int[N + 1];
@@ -200,4 +200,60 @@ def dp(n, a_num, copy):
200200
<img src="../pictures/qrcode.jpg" width=200 >
201201
</p>
202202

203-
======其他语言代码======
203+
======其他语言代码======
204+
205+
### javascript
206+
207+
[651.四键键盘](https://leetcode-cn.com/problems/4-keys-keyboard)
208+
209+
**1、第一种思路**
210+
211+
```js
212+
let maxA = function (N) {
213+
// 备忘录
214+
let memo = {}
215+
216+
let dp = function (n, a_num, copy) {
217+
if (n <= 0) {
218+
return a_num;
219+
}
220+
221+
let key = n + ',' + a_num + ',' + copy
222+
// 避免计算重叠子问题
223+
if (memo[key] !== undefined) {
224+
return memo[key]
225+
}
226+
227+
memo[key] = Math.max(
228+
dp(n - 1, a_num + 1, copy), // A
229+
dp(n - 1, a_num + copy, copy), // C-V
230+
dp(n - 2, a_num, a_num) // C-A C-C
231+
)
232+
233+
return memo[key]
234+
}
235+
236+
return dp(N, 0, 0)
237+
}
238+
```
239+
240+
**2、第二种思路**
241+
242+
```js
243+
var maxA = function (N) {
244+
let dp = new Array(N + 1);
245+
dp[0] = 0;
246+
for (let i = 1; i <= N; i++) {
247+
// 按A键盘
248+
dp[i] = dp[i - 1] + 1;
249+
for (let j = 2; j < i; j++) {
250+
// 全选 & 复制 dp[j-2],连续粘贴 i - j 次
251+
// 屏幕上共 dp[j - 2] * (i - j + 1) 个 A
252+
dp[i] = Math.max(dp[i], dp[j - 2] * (i - (j - 2) - 1));
253+
}
254+
}
255+
// N 次按键之后最多有几个 A?
256+
return dp[N];
257+
}
258+
```
259+

0 commit comments

Comments
 (0)