Skip to content

Commit e98f947

Browse files
authored
Merge branch 'youngyangyang04:master' into master
2 parents 455520b + d2f6458 commit e98f947

File tree

5 files changed

+104
-36
lines changed

5 files changed

+104
-36
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@
141141

142142
1. [字符串:344.反转字符串](./problems/0344.反转字符串.md)
143143
2. [字符串:541.反转字符串II](./problems/0541.反转字符串II.md)
144-
3. [字符串:替换数字](./problems/kama54.替换数字.md)
144+
3. [字符串:替换数字](./problems/kamacoder/0054.替换数字.md)
145145
4. [字符串:151.翻转字符串里的单词](./problems/0151.翻转字符串里的单词.md)
146-
5. [字符串:右旋字符串](./problems/kama55.右旋字符串.md)
146+
5. [字符串:右旋字符串](./problems/kamacoder/0055.右旋字符串.md)
147147
6. [帮你把KMP算法学个通透](./problems/0028.实现strStr.md)
148148
8. [字符串:459.重复的子字符串](./problems/0459.重复的子字符串.md)
149149
9. [字符串:总结篇!](./problems/字符串总结.md)
@@ -154,7 +154,7 @@
154154

155155
1. [数组:27.移除元素](./problems/0027.移除元素.md)
156156
2. [字符串:344.反转字符串](./problems/0344.反转字符串.md)
157-
3. [字符串:替换数字](./problems/kama54.替换数字.md)
157+
3. [字符串:替换数字](./problems/kamacoder/0054.替换数字.md)
158158
4. [字符串:151.翻转字符串里的单词](./problems/0151.翻转字符串里的单词.md)
159159
5. [链表:206.翻转链表](./problems/0206.翻转链表.md)
160160
6. [链表:19.删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md)

problems/0226.翻转二叉树.md

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ if (root == NULL) return root;
8181

8282
3. 确定单层递归的逻辑
8383

84-
因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
84+
因为是前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
8585

8686
```cpp
8787
swap(root->left, root->right);
@@ -348,14 +348,13 @@ class Solution:
348348
while stack:
349349
node = stack.pop()
350350
node.left, node.right = node.right, node.left
351+
if node.right:
352+
stack.append(node.right)
351353
if node.left:
352354
stack.append(node.left)
353-
if node.right:
354-
stack.append(node.right)
355355
return root
356356
```
357357

358-
359358
递归法:中序遍历:
360359
```python
361360
# Definition for a binary tree node.
@@ -374,7 +373,7 @@ class Solution:
374373
return root
375374
```
376375

377-
迭代法:中序遍历
376+
迭代法,伪中序遍历(结果是对的,看起来像是中序遍历,实际上它是前序遍历,只不过把中间节点处理逻辑放到了中间。还是要用'统一写法'才是真正的中序遍历)
378377
```python
379378
# Definition for a binary tree node.
380379
# class TreeNode:
@@ -386,18 +385,17 @@ class Solution:
386385
def invertTree(self, root: TreeNode) -> TreeNode:
387386
if not root:
388387
return None
389-
stack = [root]
388+
stack = [root]
390389
while stack:
391-
node = stack.pop()
392-
if node.left:
393-
stack.append(node.left)
394-
node.left, node.right = node.right, node.left
395-
if node.left:
396-
stack.append(node.left)
390+
node = stack.pop()
391+
if node.right:
392+
stack.append(node.right)
393+
node.left, node.right = node.right, node.left # 放到中间,依然是前序遍历
394+
if node.right:
395+
stack.append(node.right)
397396
return root
398397
```
399398

400-
401399
递归法:后序遍历:
402400
```python
403401
# Definition for a binary tree node.
@@ -416,7 +414,7 @@ class Solution:
416414
return root
417415
```
418416

419-
迭代法:后序遍历
417+
迭代法,伪后序遍历(结果是对的,看起来像是后序遍历,实际上它是前序遍历,只不过把中间节点处理逻辑放到了最后。还是要用'统一写法'才是真正的后序遍历)
420418
```python
421419
# Definition for a binary tree node.
422420
# class TreeNode:
@@ -427,23 +425,19 @@ class Solution:
427425
class Solution:
428426
def invertTree(self, root: TreeNode) -> TreeNode:
429427
if not root:
430-
return None
431-
stack = [root]
428+
return None
429+
stack = [root]
432430
while stack:
433-
node = stack.pop()
431+
node = stack.pop()
432+
if node.right:
433+
stack.append(node.right)
434434
if node.left:
435435
stack.append(node.left)
436-
if node.right:
437-
stack.append(node.right)
438436
node.left, node.right = node.right, node.left
439437

440438
return root
441439
```
442440

443-
444-
445-
446-
447441
迭代法:广度优先遍历(层序遍历):
448442
```python
449443
# Definition for a binary tree node.

problems/0583.两个字符串的删除操作.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
3535

36-
这里dp数组的定义有点点绕,大家要撸清思路
36+
这里dp数组的定义有点点绕,大家要理清思路
3737

3838
2. 确定递推公式
3939

@@ -255,6 +255,8 @@ class Solution(object):
255255
```
256256
### Go:
257257
258+
动态规划一
259+
258260
```go
259261
func minDistance(word1 string, word2 string) int {
260262
dp := make([][]int, len(word1)+1)
@@ -287,8 +289,40 @@ func min(a, b int) int {
287289
return b
288290
}
289291
```
292+
293+
294+
动态规划二
295+
296+
```go
297+
func minDistance(word1 string, word2 string) int {
298+
dp := make([][]int, len(word1) + 1)
299+
for i := range dp {
300+
dp[i] = make([]int, len(word2) + 1)
301+
}
302+
for i := 1; i <= len(word1); i++ {
303+
for j := 1; j <= len(word2); j++ {
304+
if word1[i-1] == word2[j-1] {
305+
dp[i][j] = dp[i-1][j-1] + 1
306+
} else {
307+
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
308+
}
309+
}
310+
}
311+
return len(word1) + len(word2) - dp[len(word1)][len(word2)] * 2
312+
}
313+
314+
func max(x, y int) int {
315+
if x > y {
316+
return x
317+
}
318+
return y
319+
}
320+
```
321+
322+
290323
### JavaScript:
291324

325+
292326
```javascript
293327
// 方法一
294328
var minDistance = (word1, word2) => {

problems/二叉树的迭代遍历.md

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,14 +240,14 @@ class Solution {
240240
# 前序遍历-迭代-LC144_二叉树的前序遍历
241241
class Solution:
242242
def preorderTraversal(self, root: TreeNode) -> List[int]:
243-
# 根结点为空则返回空列表
243+
# 根节点为空则返回空列表
244244
if not root:
245245
return []
246246
stack = [root]
247247
result = []
248248
while stack:
249249
node = stack.pop()
250-
# 中结点先处理
250+
# 中节点先处理
251251
result.append(node.val)
252252
# 右孩子先入栈
253253
if node.right:
@@ -262,25 +262,27 @@ class Solution:
262262
# 中序遍历-迭代-LC94_二叉树的中序遍历
263263
class Solution:
264264
def inorderTraversal(self, root: TreeNode) -> List[int]:
265+
265266
if not root:
266267
return []
267-
stack = [] # 不能提前将root结点加入stack中
268+
stack = [] # 不能提前将root节点加入stack中
269+
268270
result = []
269271
cur = root
270272
while cur or stack:
271-
# 先迭代访问最底层的左子树结点
273+
# 先迭代访问最底层的左子树节点
272274
if cur:
273275
stack.append(cur)
274276
cur = cur.left
275-
# 到达最左结点后处理栈顶结点
277+
# 到达最左节点后处理栈顶节点
276278
else:
277279
cur = stack.pop()
278280
result.append(cur.val)
279-
# 取栈顶元素右结点
281+
# 取栈顶元素右节点
280282
cur = cur.right
281283
return result
282284
```
283-
```python
285+
```python
284286

285287
# 后序遍历-迭代-LC145_二叉树的后序遍历
286288
class Solution:
@@ -291,7 +293,7 @@ class Solution:
291293
result = []
292294
while stack:
293295
node = stack.pop()
294-
# 中结点先处理
296+
# 中节点先处理
295297
result.append(node.val)
296298
# 左孩子先入栈
297299
if node.left:
@@ -303,6 +305,44 @@ class Solution:
303305
return result[::-1]
304306
```
305307

308+
#### Python 后序遍历的迭代新解法:
309+
* 本解法不同于前文介绍的`逆转前序遍历调整后的结果`,而是采用了对每个节点直接处理。这个实现方法在面试中不容易写出来,在下一节,我将改造本代码,奉上代码更简洁、更套路化、更容易实现的统一方法。
310+
311+
```python
312+
class Solution:
313+
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
314+
values = []
315+
stack = []
316+
popped_nodes = set() # 记录值已经被收割了的 nodes,这是关键,已经被收割的节点还在树中,还会被访问到,但逻辑上已经等同于 null 节点。
317+
current = root
318+
319+
while current or stack:
320+
if current: # 一次处理完一个节点和他的左右儿子节点,不处理孙子节点,孙子节点由左右儿子等会分别处理。
321+
stack.append(current) # 入栈自己
322+
323+
if current.right:
324+
stack.append(current.right) # 入栈右儿子
325+
326+
if current.left: # 因为栈是后进先出,后序是‘左右中’,所以后加左儿子
327+
stack.append(current.left) # 入栈左儿子
328+
329+
current = None # 会导致后面A处出栈
330+
continue
331+
332+
node = stack.pop() # A处,出的是左儿子,如果无左儿子,出的就是右儿子,如果连右儿子也没有,出的就是自己了。
333+
334+
# 如果 node 是叶子节点,就可以收割了;如果左右儿子都已经被收割了,也可以收割
335+
if (node.left is None or node.left in popped_nodes) and \
336+
(node.right is None or node.right in popped_nodes):
337+
popped_nodes.add(node)
338+
values.append(node.val)
339+
continue
340+
341+
current = node # 不符合收割条件,说明 node 下还有未入栈的儿子,就去入栈
342+
343+
return values
344+
```
345+
306346
### Go:
307347

308348
> 迭代法前序遍历

problems/栈与队列总结.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ cd a/b/c/../../
107107
设计单调队列的时候,pop,和push操作要保持如下规则:
108108

109109
1. pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
110-
2. push(value):如果push的元素value大于入口元素的数值,那么就将队列出口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
110+
2. push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
111111

112112
保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。
113113

0 commit comments

Comments
 (0)