Merge branch 'youngyangyang04:master' into master

This commit is contained in:
Po1vre
2024-12-06 14:34:42 +08:00
committed by GitHub
5 changed files with 104 additions and 36 deletions

View File

@ -141,9 +141,9 @@
1. [字符串344.反转字符串](./problems/0344.反转字符串.md)
2. [字符串541.反转字符串II](./problems/0541.反转字符串II.md)
3. [字符串:替换数字](./problems/kama54.替换数字.md)
3. [字符串:替换数字](./problems/kamacoder/0054.替换数字.md)
4. [字符串151.翻转字符串里的单词](./problems/0151.翻转字符串里的单词.md)
5. [字符串:右旋字符串](./problems/kama55.右旋字符串.md)
5. [字符串:右旋字符串](./problems/kamacoder/0055.右旋字符串.md)
6. [帮你把KMP算法学个通透](./problems/0028.实现strStr.md)
8. [字符串459.重复的子字符串](./problems/0459.重复的子字符串.md)
9. [字符串:总结篇!](./problems/字符串总结.md)
@ -154,7 +154,7 @@
1. [数组27.移除元素](./problems/0027.移除元素.md)
2. [字符串344.反转字符串](./problems/0344.反转字符串.md)
3. [字符串:替换数字](./problems/kama54.替换数字.md)
3. [字符串:替换数字](./problems/kamacoder/0054.替换数字.md)
4. [字符串151.翻转字符串里的单词](./problems/0151.翻转字符串里的单词.md)
5. [链表206.翻转链表](./problems/0206.翻转链表.md)
6. [链表19.删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md)

View File

@ -81,7 +81,7 @@ if (root == NULL) return root;
3. 确定单层递归的逻辑
因为是前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
因为是前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
```cpp
swap(root->left, root->right);
@ -348,14 +348,13 @@ class Solution:
while stack:
node = stack.pop()
node.left, node.right = node.right, node.left
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return root
```
递归法:中序遍历:
```python
# Definition for a binary tree node.
@ -374,7 +373,7 @@ class Solution:
return root
```
迭代法中序遍历:
迭代法,伪中序遍历(结果是对的,看起来像是中序遍历,实际上它是前序遍历,只不过把中间节点处理逻辑放到了中间。还是要用'统一写法'才是真正的中序遍历)
```python
# Definition for a binary tree node.
# class TreeNode:
@ -389,15 +388,14 @@ class Solution:
stack = [root]
while stack:
node = stack.pop()
if node.left:
stack.append(node.left)
node.left, node.right = node.right, node.left
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
node.left, node.right = node.right, node.left # 放到中间,依然是前序遍历
if node.right:
stack.append(node.right)
return root
```
递归法:后序遍历:
```python
# Definition for a binary tree node.
@ -416,7 +414,7 @@ class Solution:
return root
```
迭代法后序遍历:
迭代法,伪后序遍历(结果是对的,看起来像是后序遍历,实际上它是前序遍历,只不过把中间节点处理逻辑放到了最后。还是要用'统一写法'才是真正的后序遍历)
```python
# Definition for a binary tree node.
# class TreeNode:
@ -431,19 +429,15 @@ class Solution:
stack = [root]
while stack:
node = stack.pop()
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
node.left, node.right = node.right, node.left
return root
```
迭代法:广度优先遍历(层序遍历):
```python
# Definition for a binary tree node.

View File

@ -33,7 +33,7 @@
dp[i][j]以i-1为结尾的字符串word1和以j-1位结尾的字符串word2想要达到相等所需要删除元素的最少次数。
这里dp数组的定义有点点绕大家要清思路。
这里dp数组的定义有点点绕大家要清思路。
2. 确定递推公式
@ -255,6 +255,8 @@ class Solution(object):
```
### Go
动态规划一
```go
func minDistance(word1 string, word2 string) int {
dp := make([][]int, len(word1)+1)
@ -287,8 +289,40 @@ func min(a, b int) int {
return b
}
```
动态规划二
```go
func minDistance(word1 string, word2 string) int {
dp := make([][]int, len(word1) + 1)
for i := range dp {
dp[i] = make([]int, len(word2) + 1)
}
for i := 1; i <= len(word1); i++ {
for j := 1; j <= len(word2); j++ {
if word1[i-1] == word2[j-1] {
dp[i][j] = dp[i-1][j-1] + 1
} else {
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
}
}
}
return len(word1) + len(word2) - dp[len(word1)][len(word2)] * 2
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
```
### JavaScript
```javascript
// 方法一
var minDistance = (word1, word2) => {

View File

@ -240,14 +240,14 @@ class Solution {
# 前序遍历-迭代-LC144_二叉树的前序遍历
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
# 根点为空则返回空列表
# 根点为空则返回空列表
if not root:
return []
stack = [root]
result = []
while stack:
node = stack.pop()
# 中点先处理
# 中点先处理
result.append(node.val)
# 右孩子先入栈
if node.right:
@ -262,25 +262,27 @@ class Solution:
# 中序遍历-迭代-LC94_二叉树的中序遍历
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = [] # 不能提前将root点加入stack中
stack = [] # 不能提前将root点加入stack中
result = []
cur = root
while cur or stack:
# 先迭代访问最底层的左子树
# 先迭代访问最底层的左子树
if cur:
stack.append(cur)
cur = cur.left
# 到达最左点后处理栈顶
# 到达最左点后处理栈顶
else:
cur = stack.pop()
result.append(cur.val)
# 取栈顶元素右
# 取栈顶元素右
cur = cur.right
return result
```
```python
```python
# 后序遍历-迭代-LC145_二叉树的后序遍历
class Solution:
@ -291,7 +293,7 @@ class Solution:
result = []
while stack:
node = stack.pop()
# 中点先处理
# 中点先处理
result.append(node.val)
# 左孩子先入栈
if node.left:
@ -303,6 +305,44 @@ class Solution:
return result[::-1]
```
#### Python 后序遍历的迭代新解法:
* 本解法不同于前文介绍的`逆转前序遍历调整后的结果`而是采用了对每个节点直接处理这个实现方法在面试中不容易写出来在下一节我将改造本代码奉上代码更简洁更套路化更容易实现的统一方法
```python
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
values = []
stack = []
popped_nodes = set() # 记录值已经被收割了的 nodes这是关键已经被收割的节点还在树中还会被访问到但逻辑上已经等同于 null 节点。
current = root
while current or stack:
if current: # 一次处理完一个节点和他的左右儿子节点,不处理孙子节点,孙子节点由左右儿子等会分别处理。
stack.append(current) # 入栈自己
if current.right:
stack.append(current.right) # 入栈右儿子
if current.left: # 因为栈是后进先出,后序是‘左右中’,所以后加左儿子
stack.append(current.left) # 入栈左儿子
current = None # 会导致后面A处出栈
continue
node = stack.pop() # A处出的是左儿子如果无左儿子出的就是右儿子如果连右儿子也没有出的就是自己了。
# 如果 node 是叶子节点,就可以收割了;如果左右儿子都已经被收割了,也可以收割
if (node.left is None or node.left in popped_nodes) and \
(node.right is None or node.right in popped_nodes):
popped_nodes.add(node)
values.append(node.val)
continue
current = node # 不符合收割条件,说明 node 下还有未入栈的儿子,就去入栈
return values
```
### Go
> 迭代法前序遍历

View File

@ -107,7 +107,7 @@ cd a/b/c/../../
设计单调队列的时候pop和push操作要保持如下规则
1. pop(value)如果窗口移除的元素value等于单调队列的出口元素那么队列弹出元素否则不用任何操作
2. push(value)如果push的元素value大于入口元素的数值那么就将队列口的元素弹出直到push元素的数值小于等于队列入口元素的数值为止
2. push(value)如果push的元素value大于入口元素的数值那么就将队列口的元素弹出直到push元素的数值小于等于队列入口元素的数值为止
保持如上规则每次窗口移动的时候只要问que.front()就可以返回当前窗口的最大值。