Merge branch 'master' of github.com:flames519/leetcode-master

This commit is contained in:
qingyi.liu
2021-06-22 10:39:31 +08:00
85 changed files with 3413 additions and 331 deletions

View File

@ -17,6 +17,11 @@
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
</p>
<p align="center">
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ" target="_blank">
<img src="./pics/知识星球.png" width="600"/>
</a>
# LeetCode 刷题攻略
@ -120,6 +125,10 @@
4. [马上秋招了,慌得很!](https://mp.weixin.qq.com/s/7q7W8Cb2-a5U5atZdOnOFA)
5. [Carl看了上百份简历总结了这些](https://mp.weixin.qq.com/s/sJa87MZD28piCOVMFkIbwQ)
6. [面试中遇到了发散性问题.....](https://mp.weixin.qq.com/s/SSonDxi2pjkSVwHNzZswng)
7. [英语到底重不重要!](https://mp.weixin.qq.com/s/1PRZiyF_-TVA-ipwDNjdKw)
8. [计算机专业要不要读研!](https://mp.weixin.qq.com/s/c9v1L3IjqiXtkNH7sOMAdg)
9. [秋招和提前批都越来越提前了....](https://mp.weixin.qq.com/s/SNFiRDx8CKyjhTPlys6ywQ)
## 数组
@ -379,9 +388,12 @@
54. [动态规划:最长回文子序列](./problems/0516.最长回文子序列.md)
55. [动态规划总结篇](./problems/动态规划总结篇.md)
(持续更新中....
## 单调栈
1. [每日温度](./problems/0739.每日温度.md)
## 图论
## 十大排序

View File

@ -107,7 +107,7 @@ public int[] twoSum(int[] nums, int target) {
Python
```python3
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hashmap={}

View File

@ -321,6 +321,59 @@ class Solution:
backtrack(board)
```
Python3:
```python3
class Solution:
def __init__(self) -> None:
self.board = []
def isValid(self, row: int, col: int, target: int) -> bool:
for idx in range(len(self.board)):
# 同列是否重复
if self.board[idx][col] == str(target):
return False
# 同行是否重复
if self.board[row][idx] == str(target):
return False
# 9宫格里是否重复
box_row, box_col = (row // 3) * 3 + idx // 3, (col // 3) * 3 + idx % 3
if self.board[box_row][box_col] == str(target):
return False
return True
def getPlace(self) -> List[int]:
for row in range(len(self.board)):
for col in range(len(self.board)):
if self.board[row][col] == ".":
return [row, col]
return [-1, -1]
def isSolved(self) -> bool:
row, col = self.getPlace() # 找个空位置
if row == -1 and col == -1: # 没有空位置,棋盘被填满的
return True
for i in range(1, 10):
if self.isValid(row, col, i): # 检查这个空位置放i是否合适
self.board[row][col] = str(i) # 放i
if self.isSolved(): # 合适,立刻返回, 填下一个空位置。
return True
self.board[row][col] = "." # 不合适,回溯
return False # 空位置没法解决
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
if board is None or len(board) == 0:
return
self.board = board
self.isSolved()
```
Go
Javascript:

View File

@ -353,14 +353,6 @@ class Solution {
}
```
## 其他语言版本
Java
Python
Go
```Go

View File

@ -95,10 +95,47 @@ public:
Java
```java
/**
* 1.dp[i]代表当前下标对应的最大值
* 2.递推公式 dp[i] = max (dp[i-1]+nums[i],nums[i]) res = max(res,dp[i])
* 3.初始化 都为 0
* 4.遍历方向,从前往后
* 5.举例推导结果。。。
*
* @param nums
* @return
*/
public static int maxSubArray(int[] nums) {
if (nums.length == 0) {
return 0;
}
int res = nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
res = res > dp[i] ? res : dp[i];
}
return res;
}
```
Python
```python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
dp = [0] * len(nums)
dp[0] = nums[0]
result = dp[0]
for i in range(1, len(nums)):
dp[i] = max(dp[i-1] + nums[i], nums[i]) #状态转移公式
result = max(result, dp[i]) #result 保存dp[i]的最大值
return result
```
Go

View File

@ -308,6 +308,27 @@ func uniquePaths(m int, n int) int {
}
```
Javascript
```Javascript
var uniquePaths = function(m, n) {
const dp = Array(m).fill().map(item => Array(n))
for (let i = 0; i < m; ++i) {
dp[i][0] = 1
}
for (let i = 0; i < n; ++i) {
dp[0][i] = 1
}
for (let i = 1; i < m; ++i) {
for (let j = 1; j < n; ++j) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
}
}
return dp[m - 1][n - 1]
};
```
-----------------------

View File

@ -279,6 +279,30 @@ func uniquePathsWithObstacles(obstacleGrid [][]int) int {
```
Javascript
``` Javascript
var uniquePathsWithObstacles = function(obstacleGrid) {
const m = obstacleGrid.length
const n = obstacleGrid[0].length
const dp = Array(m).fill().map(item => Array(n).fill(0))
for (let i = 0; i < m && obstacleGrid[i][0] === 0; ++i) {
dp[i][0] = 1
}
for (let i = 0; i < n && obstacleGrid[0][i] === 0; ++i) {
dp[0][i] = 1
}
for (let i = 1; i < m; ++i) {
for (let j = 1; j < n; ++j) {
dp[i][j] = obstacleGrid[i][j] === 1 ? 0 : dp[i - 1][j] + dp[i][j - 1]
}
}
return dp[m - 1][n - 1]
};
```
-----------------------

View File

@ -148,9 +148,44 @@ class Solution {
Python
Go
```python3
class Solution:
def climbStairs(self, n: int) -> int:
dp = [0]*(n + 1)
dp[0] = 1
m = 2
# 遍历背包
for j in range(n + 1):
# 遍历物品
for step in range(1, m + 1):
if j >= step:
dp[j] += dp[j - step]
return dp[n]
```
Go
```go
func climbStairs(n int) int {
//定义
dp := make([]int, n+1)
//初始化
dp[0] = 1
// 本题物品只有两个1,2
m := 2
// 遍历顺序
for j := 1; j <= n; j++ { //先遍历背包
for i := 1; i <= m; i++ { //再遍历物品
if j >= i {
dp[j] += dp[j-i]
}
//fmt.Println(dp)
}
}
return dp[n]
}
```
-----------------------

View File

@ -51,7 +51,9 @@ exection -> execution (插入 'u')
接下来我依然使用动规五部曲,对本题做一个详细的分析:
1. 确定dp数组dp table以及下标的含义
-----------------------
### 1. 确定dp数组dp table以及下标的含义
**dp[i][j] 表示以下标i-1为结尾的字符串word1和以下标j-1为结尾的字符串word2最近编辑距离为dp[i][j]**
@ -59,49 +61,65 @@ exection -> execution (插入 'u')
用i来表示也可以 但我统一以下标i-1为结尾的字符串在下面的递归公式中会容易理解一点。
2. 确定递推公式
-----------------------
### 2. 确定递推公式
在确定递推公式的时候,首先要考虑清楚编辑的几种操作,整理如下:
* if (word1[i - 1] == word2[j - 1])
* 不操作
* if (word1[i - 1] != word2[j - 1])
*
*
*
```
if (word1[i - 1] == word2[j - 1])
不操作
if (word1[i - 1] != word2[j - 1])
```
也就是如上种情况。
也就是如上4种情况。
if (word1[i - 1] == word2[j - 1]) 那么说明不用任何编辑dp[i][j] 就应该是 dp[i - 1][j - 1],即dp[i][j] = dp[i - 1][j - 1];
`if (word1[i - 1] == word2[j - 1])` 那么说明不用任何编辑,`dp[i][j]` 就应该是 `dp[i - 1][j - 1]`,即`dp[i][j] = dp[i - 1][j - 1];`
此时可能有同学有点不明白为啥要即dp[i][j] = dp[i - 1][j - 1]呢?
此时可能有同学有点不明白,为啥要即`dp[i][j] = dp[i - 1][j - 1]`呢?
那么就在回顾上面讲过的dp[i][j]的定义word1[i - 1] 与 word2[j - 1]相等了那么就不用编辑了以下标i-2为结尾的字符串word1和以下标j-2为结尾的字符串word2的最近编辑距离dp[i - 1][j - 1] 就是 dp[i][j]了。
那么就在回顾上面讲过的`dp[i][j]`的定义,`word1[i - 1]``word2[j - 1]`相等了那么就不用编辑了以下标i-2为结尾的字符串word1和以下标j-2为结尾的字符串`word2`的最近编辑距离`dp[i - 1][j - 1]`就是 `dp[i][j]`了。
在下面的讲解中如果哪里看不懂就回想一下dp[i][j]的定义,就明白了。
在下面的讲解中,如果哪里看不懂,就回想一下`dp[i][j]`的定义,就明白了。
**在整个动规的过程中最为关键就是正确理解dp[i][j]的定义!**
**在整个动规的过程中,最为关键就是正确理解`dp[i][j]`的定义!**
if (word1[i - 1] != word2[j - 1]),此时就需要编辑了,如何编辑呢?
操作一word1增加一个元素使其word1[i - 1]word2[j - 1]相同那么就是以下标i-2为结尾的word1 与 i-1为结尾的word2的最近编辑距离 加上一个增加元素的操作。
`if (word1[i - 1] != word2[j - 1])`,此时就需要编辑了,如何编辑呢?
即 dp[i][j] = dp[i - 1][j] + 1;
操作一word1增加一个元素使其word1[i - 1]与word2[j - 1]相同那么就是以下标i-2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 加上一个增加元素的操作。
`dp[i][j] = dp[i - 1][j] + 1;`
操作二word2添加一个元素使其word1[i - 1]与word2[j - 1]相同那么就是以下标i-1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 加上一个增加元素的操作。
即 dp[i][j] = dp[i][j - 1] + 1;
`dp[i][j] = dp[i][j - 1] + 1;`
这里有同学发现了,怎么都是添加元素,删除元素去哪了。
**word2添加一个元素相当于word1删除一个元素**,例如 word1 = "ad" word2 = "a"word2添加一个元素d也就是相当于word1删除一个元素d操作数是一样
**word2添加一个元素相当于word1删除一个元素**,例如 `word1 = "ad" word2 = "a"``word1`删除元素`'d'``word2`添加一个元素`'d'`,变成`word1="a", word2="ad"` 最终的操作数是一样! dp数组如下图所示意的
操作三替换元素word1替换word1[i - 1]使其与word2[j - 1]相同此时不用增加元素那么以下标i-2为结尾的word1 与 j-2为结尾的word2的最近编辑距离 加上一个替换元素的操作。
```
a a d
+-----+-----+ +-----+-----+-----+
| 0 | 1 | | 0 | 1 | 2 |
+-----+-----+ ===> +-----+-----+-----+
a | 1 | 0 | a | 1 | 0 | 1 |
+-----+-----+ +-----+-----+-----+
d | 2 | 1 |
+-----+-----+
```
即 dp[i][j] = dp[i - 1][j - 1] + 1;
操作三:替换元素,`word1`替换`word1[i - 1]`,使其与`word2[j - 1]`相同,此时不用增加元素,那么以下标`i-2`为结尾的`word1``j-2`为结尾的`word2`的最近编辑距离 加上一个替换元素的操作。
综上,当 if (word1[i - 1] != word2[j - 1]) 时取最小的,即:dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
`dp[i][j] = dp[i - 1][j - 1] + 1;`
综上,当 `if (word1[i - 1] != word2[j - 1])` 时取最小的,即:`dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;`
递归公式代码如下:
@ -114,9 +132,12 @@ else {
}
```
3. dp数组如何初始化
---
在回顾一下dp[i][j]的定义。
### 3. dp数组如何初始化
再回顾一下dp[i][j]的定义:
**dp[i][j] 表示以下标i-1为结尾的字符串word1和以下标j-1为结尾的字符串word2最近编辑距离为dp[i][j]**。
@ -135,14 +156,16 @@ for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
```
4. 确定遍历顺序
-----------------------
### 4. 确定遍历顺序
从如下四个递推公式:
* dp[i][j] = dp[i - 1][j - 1]
* dp[i][j] = dp[i - 1][j - 1] + 1
* dp[i][j] = dp[i][j - 1] + 1
* dp[i][j] = dp[i - 1][j] + 1
* `dp[i][j] = dp[i - 1][j - 1]`
* `dp[i][j] = dp[i - 1][j - 1] + 1`
* `dp[i][j] = dp[i][j - 1] + 1`
* `dp[i][j] = dp[i - 1][j] + 1`
可以看出dp[i][j]是依赖左方,上方和左上方元素的,如图:
@ -164,10 +187,12 @@ for (int i = 1; i <= word1.size(); i++) {
}
}
```
-----------------------
5. 举例推导dp数组
### 5. 举例推导dp数组
以示例1输入word1 = "horse", word2 = "ros"为例dp矩阵状态图如下
以示例1为例输入`word1 = "horse", word2 = "ros"`为例dp矩阵状态图如下
![72.编辑距离1](https://img-blog.csdnimg.cn/20210114162132300.jpg)
@ -195,7 +220,7 @@ public:
};
```
-----------------------
## 其他语言版本
@ -228,7 +253,22 @@ public int minDistance(String word1, String word2) {
```
Python
```python
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
dp = [[0] * (len(word2)+1) for _ in range(len(word1)+1)]
for i in range(len(word1)+1):
dp[i][0] = i
for j in range(len(word2)+1):
dp[0][j] = j
for i in range(1, len(word1)+1):
for j in range(1, len(word2)+1):
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1
return dp[-1][-1]
```
Go
```Go

View File

@ -338,6 +338,46 @@ class Solution(object):
return ans```
```
```python3
class Solution:
def __init__(self) -> None:
self.s = ""
self.res = []
def isVaild(self, s: str) -> bool:
if len(s) > 1 and s[0] == "0":
return False
if 0 <= int(s) <= 255:
return True
return False
def backTrack(self, path: List[str], start: int) -> None:
if start == len(self.s) and len(path) == 4:
self.res.append(".".join(path))
return
for end in range(start + 1, len(self.s) + 1):
# 剪枝
# 保证切割完s没有剩余的字符。
if len(self.s) - end > 3 * (4 - len(path) - 1):
continue
if self.isVaild(self.s[start:end]):
# 在参数处,更新状态,实则创建一个新的变量
# 不会影响当前的状态当前的path变量没有改变
# 因此递归完不用path.pop()
self.backTrack(path + [self.s[start:end]], end)
def restoreIpAddresses(self, s: str) -> List[str]:
# prune
if len(s) > 3 * 4:
return []
self.s = s
self.backTrack([], 0)
return self.res
```
JavaScript
```js

View File

@ -98,15 +98,13 @@ class Solution:
out_list = []
while quene:
length = len(queue)
in_list = []
for _ in range(len(quene)):
node = quene.pop(0)
in_list.append(node.val)
if node.left:
quene.append(node.left)
if node.right:
quene.append(node.right)
for _ in range(length):
curnode = queue.pop(0) # (默认移除列表最后一个元素)这里需要移除队列最头上的那个
in_list.append(curnode.val)
if curnode.left: queue.append(curnode.left)
if curnode.right: queue.append(curnode.right)
out_list.append(in_list)
return out_list
@ -629,6 +627,27 @@ public:
}
};
```
python代码
```python
class Solution:
def largestValues(self, root: TreeNode) -> List[int]:
if root is None:
return []
queue = [root]
out_list = []
while queue:
length = len(queue)
in_list = []
for _ in range(length):
curnode = queue.pop(0)
in_list.append(curnode.val)
if curnode.left: queue.append(curnode.left)
if curnode.right: queue.append(curnode.right)
out_list.append(max(in_list))
return out_list
```
javascript代码
```javascript
@ -714,6 +733,42 @@ public:
};
```
python代码
```python
# 层序遍历解法
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return None
queue = [root]
while queue:
n = len(queue)
for i in range(n):
node = queue.pop(0)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
if i == n - 1:
break
node.next = queue[0]
return root
# 链表解法
class Solution:
def connect(self, root: 'Node') -> 'Node':
first = root
while first:
cur = first
while cur: # 遍历每一层的节点
if cur.left: cur.left.next = cur.right # 找左节点的next
if cur.right and cur.next: cur.right.next = cur.next.left # 找右节点的next
cur = cur.next # cur同层移动到下一节点
first = first.left # 从本层扩展到下一层
return root
```
## 117.填充每个节点的下一个右侧节点指针II
题目地址https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/
@ -755,7 +810,48 @@ public:
}
};
```
python代码
```python
# 层序遍历解法
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return None
queue = [root]
while queue: # 遍历每一层
length = len(queue)
tail = None # 每一层维护一个尾节点
for i in range(length): # 遍历当前层
curnode = queue.pop(0)
if tail:
tail.next = curnode # 让尾节点指向当前节点
tail = curnode # 让当前节点成为尾节点
if curnode.left : queue.append(curnode.left)
if curnode.right: queue.append(curnode.right)
return root
# 链表解法
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return None
first = root
while first: # 遍历每一层
dummyHead = Node(None) # 为下一行创建一个虚拟头节点,相当于下一行所有节点链表的头结点(每一层都会创建)
tail = dummyHead # 为下一行维护一个尾节点指针(初始化是虚拟节点)
cur = first
while cur: # 遍历当前层的节点
if cur.left: # 链接下一行的节点
tail.next = cur.left
tail = tail.next
if cur.right:
tail.next = cur.right
tail = tail.next
cur = cur.next # cur同层移动到下一节点
first = dummyHead.next # 此处为换行操作,更新到下一行
return root
```
## 总结

View File

@ -193,40 +193,6 @@ public:
};
```
使用栈来模拟后序遍历依然可以
```C++
class Solution {
public:
int maxDepth(TreeNode* root) {
stack<TreeNode*> st;
if (root != NULL) st.push(root);
int depth = 0;
int result = 0;
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
st.pop();
st.push(node); // 中
st.push(NULL);
depth++;
if (node->right) st.push(node->right); // 右
if (node->left) st.push(node->left); // 左
} else {
st.pop();
node = st.top();
st.pop();
depth--;
}
result = result > depth ? result : depth;
}
return result;
}
};
```
## 其他语言版本

View File

@ -693,6 +693,70 @@ class Solution:
return root
```
Go
> 106 从中序与后序遍历序列构造二叉树
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func buildTree(inorder []int, postorder []int) *TreeNode {
if len(inorder)<1||len(postorder)<1{return nil}
//先找到根节点(后续遍历的最后一个就是根节点)
nodeValue:=postorder[len(postorder)-1]
//从中序遍历中找到一分为二的点,左边为左子树,右边为右子树
left:=findRootIndex(inorder,nodeValue)
//构造root
root:=&TreeNode{Val: nodeValue,
Left: buildTree(inorder[:left],postorder[:left]),//将后续遍历一分为二,左边为左子树,右边为右子树
Right: buildTree(inorder[left+1:],postorder[left:len(postorder)-1])}
return root
}
func findRootIndex(inorder []int,target int) (index int){
for i:=0;i<len(inorder);i++{
if target==inorder[i]{
return i
}
}
return -1
}
```
> 105 从前序与中序遍历序列构造二叉树
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func buildTree(preorder []int, inorder []int) *TreeNode {
if len(preorder)<1||len(inorder)<1{return nil}
left:=findRootIndex(preorder[0],inorder)
root:=&TreeNode{
Val: preorder[0],
Left: buildTree(preorder[1:left+1],inorder[:left]),
Right: buildTree(preorder[left+1:],inorder[left+1:])}
return root
}
func findRootIndex(target int,inorder []int) int{
for i:=0;i<len(inorder);i++{
if target==inorder[i]{
return i
}
}
return -1
}
```
JavaScript
@ -711,6 +775,20 @@ var buildTree = function(inorder, postorder) {
};
```
从前序与中序遍历序列构造二叉树
```javascript
var buildTree = function(preorder, inorder) {
if(!preorder.length)
return null;
let root = new TreeNode(preorder[0]);
let mid = inorder.findIndex((number) => number === root.val);
root.left = buildTree(preorder.slice(1, mid + 1), inorder.slice(0, mid));
root.right = buildTree(preorder.slice(mid + 1, preorder.length), inorder.slice(mid + 1, inorder.length));
return root;
};
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -486,6 +486,92 @@ class Solution:
Go
> 112. 路径总和
```go
//递归法
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func hasPathSum(root *TreeNode, targetSum int) bool {
var flage bool //找没找到的标志
if root==nil{
return flage
}
pathSum(root,0,targetSum,&flage)
return flage
}
func pathSum(root *TreeNode, sum int,targetSum int,flage *bool){
sum+=root.Val
if root.Left==nil&&root.Right==nil&&sum==targetSum{
*flage=true
return
}
if root.Left!=nil&&!(*flage){//左节点不为空且还没找到
pathSum(root.Left,sum,targetSum,flage)
}
if root.Right!=nil&&!(*flage){//右节点不为空且没找到
pathSum(root.Right,sum,targetSum,flage)
}
}
```
> 113 递归法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func pathSum(root *TreeNode, targetSum int) [][]int {
var result [][]int//最终结果
if root==nil{
return result
}
var sumNodes []int//经过路径的节点集合
hasPathSum(root,&sumNodes,targetSum,&result)
return result
}
func hasPathSum(root *TreeNode,sumNodes *[]int,targetSum int,result *[][]int){
*sumNodes=append(*sumNodes,root.Val)
if root.Left==nil&&root.Right==nil{//叶子节点
fmt.Println(*sumNodes)
var sum int
var number int
for k,v:=range *sumNodes{//求该路径节点的和
sum+=v
number=k
}
tempNodes:=make([]int,number+1)//新的nodes接受指针里的值防止最终指针里的值发生变动导致最后的结果都是最后一个sumNodes的值
for k,v:=range *sumNodes{
tempNodes[k]=v
}
if sum==targetSum{
*result=append(*result,tempNodes)
}
}
if root.Left!=nil{
hasPathSum(root.Left,sumNodes,targetSum,result)
*sumNodes=(*sumNodes)[:len(*sumNodes)-1]//回溯
}
if root.Right!=nil{
hasPathSum(root.Right,sumNodes,targetSum,result)
*sumNodes=(*sumNodes)[:len(*sumNodes)-1]//回溯
}
}
```
JavaScript
0112.路径总和

View File

@ -145,10 +145,46 @@ public:
Java
```java
class Solution {
public int numDistinct(String s, String t) {
int[][] dp = new int[s.length() + 1][t.length() + 1];
for (int i = 0; i < s.length() + 1; i++) {
dp[i][0] = 1;
}
for (int i = 1; i < s.length() + 1; i++) {
for (int j = 1; j < t.length() + 1; j++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
}else{
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[s.length()][t.length()];
}
}
```
Python
```python
class Solution:
def numDistinct(self, s: str, t: str) -> int:
dp = [[0] * (len(t)+1) for _ in range(len(s)+1)]
for i in range(len(s)):
dp[i][0] = 1
for j in range(1, len(t)):
dp[0][j] = 0
for i in range(1, len(s)+1):
for j in range(1, len(t)+1):
if s[i-1] == t[j-1]:
dp[i][j] = dp[i-1][j-1] + dp[i-1][j]
else:
dp[i][j] = dp[i-1][j]
return dp[-1][-1]
```
Go

View File

@ -244,6 +244,47 @@ class Solution { // 动态规划解法
Python
> 贪心法:
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
low = float("inf")
result = 0
for i in range(len(prices)):
low = min(low, prices[i]) #取最左最小价格
result = max(result, prices[i] - low) #直接取最大区间利润
return result
```
> 动态规划:版本一
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
length = len(prices)
if len == 0:
return 0
dp = [[0] * 2 for _ in range(length)]
dp[0][0] = -prices[0]
dp[0][1] = 0
for i in range(1, length):
dp[i][0] = max(dp[i-1][0], -prices[i])
dp[i][1] = max(dp[i-1][1], prices[i] + dp[i-1][0])
return dp[-1][1]
```
> 动态规划:版本二
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
length = len(prices)
dp = [[0] * 2 for _ in range(2)] #注意这里只开辟了一个2 * 2大小的二维数组
dp[0][0] = -prices[0]
dp[0][1] = 0
for i in range(1, length):
dp[i % 2][0] = max(dp[(i-1) % 2][0], -prices[i])
dp[i % 2][1] = max(dp[(i-1) % 2][1], prices[i] + dp[(i-1) % 2][0])
return dp[(length-1) % 2][1]
```
Go
```Go

View File

@ -171,6 +171,33 @@ class Solution
Python
> 版本一:
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
length = len(prices)
dp = [[0] * 2 for _ in range(length)]
dp[0][0] = -prices[0]
dp[0][1] = 0
for i in range(1, length):
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) #注意这里是和121. 买卖股票的最佳时机唯一不同的地方
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])
return dp[-1][1]
```
> 版本二:
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
length = len(prices)
dp = [[0] * 2 for _ in range(2)] #注意这里只开辟了一个2 * 2大小的二维数组
dp[0][0] = -prices[0]
dp[0][1] = 0
for i in range(1, length):
dp[i % 2][0] = max(dp[(i-1) % 2][0], dp[(i-1) % 2][1] - prices[i])
dp[i % 2][1] = max(dp[(i-1) % 2][1], dp[(i-1) % 2][0] + prices[i])
return dp[(length-1) % 2][1]
```
Go

View File

@ -229,6 +229,40 @@ class Solution { // 动态规划
Python
> 版本一:
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices) == 0:
return 0
dp = [[0] * 5 for _ in range(len(prices))]
dp[0][1] = -prices[0]
dp[0][3] = -prices[0]
for i in range(1, len(prices)):
dp[i][0] = dp[i-1][0]
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])
dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])
return dp[-1][4]
```
> 版本二:
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices) == 0:
return 0
dp = [0] * 5
dp[1] = -prices[0]
dp[3] = -prices[0]
for i in range(1, len(prices)):
dp[1] = max(dp[1], dp[0] - prices[i])
dp[2] = max(dp[2], dp[1] + prices[i])
dp[3] = max(dp[3], dp[2] - prices[i])
dp[4] = max(dp[4], dp[3] + prices[i])
return dp[4]
```
Go

View File

@ -240,6 +240,25 @@ class Solution:
```
Go
```go
func canCompleteCircuit(gas []int, cost []int) int {
curSum := 0
totalSum := 0
start := 0
for i := 0; i < len(gas); i++ {
curSum += gas[i] - cost[i]
totalSum += gas[i] - cost[i]
if curSum < 0 {
start = i+1
curSum = 0
}
}
if totalSum < 0 {
return -1
}
return start
}
```
Javascript:
```Javascript

View File

@ -252,6 +252,23 @@ class Solution {
Python
```python3
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
'''排列'''
dp = [False]*(len(s) + 1)
dp[0] = True
# 遍历背包
for j in range(1, len(s) + 1):
# 遍历单词
for word in wordDict:
if j >= len(word):
dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
return dp[len(s)]
```
Go
```Go

View File

@ -50,12 +50,15 @@ https://leetcode-cn.com/problems/reverse-words-in-a-string/
* 将整个字符串反转
* 将每个单词反转
如动画所示:
举个例子,源字符串为:"the sky is blue "
![151翻转字符串里的单词](https://tva1.sinaimg.cn/large/008eGmZEly1gp0kv5gl4mg30gy0c4nbp.gif)
* 移除多余空格 : "the sky is blue"
* 字符串反转:"eulb si yks eht"
* 单词反转:"blue is sky the"
这样我们就完成了翻转字符串里的单词。
思路很明确了,我们说一说代码的实现细节,就拿移除多余空格来说,一些同学会上来写如下代码:
```C++
@ -80,13 +83,13 @@ void removeExtraSpaces(string& s) {
如果不仔细琢磨一下erase的时间复杂读还以为以上的代码是O(n)的时间复杂度呢。
想一下真正的时间复杂度是多少一个erase本来就是O(n)的操作erase实现原理题目[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA)最优的算法来移除元素也要O(n)。
想一下真正的时间复杂度是多少一个erase本来就是O(n)的操作erase实现原理题目[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)最优的算法来移除元素也要O(n)。
erase操作上面还套了一个for循环那么以上代码移除冗余空格的代码时间复杂度为O(n^2)。
那么使用双指针法来去移除空格最后resize重新设置一下字符串的大小就可以做到O(n)的时间复杂度。
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA)是如何移除元素的。
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)是如何移除元素的。
那么使用双指针来移除冗余空格代码如下: fastIndex走的快slowIndex走的慢最后slowIndex就标记着移除多余空格后新字符串的长度。
@ -122,7 +125,7 @@ void removeExtraSpaces(string& s) {
此时我们已经实现了removeExtraSpaces函数来移除冗余空格。
还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[字符串:这道题目,使用库函数一行代码搞定](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA)和[字符串:简单的反转还不够!](https://mp.weixin.qq.com/s/XGSk1GyPWhfqj2g7Cb1Vgw)里已经讲过了。
还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)和[541.反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ)里已经讲过了。
代码如下:
@ -135,11 +138,8 @@ void reverse(string& s, int start, int end) {
}
```
## 本题C++整体代码
本题C++整体代码
效率:
<img src='https://code-thinking.cdn.bcebos.com/pics/151_%E7%BF%BB%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%87%8C%E7%9A%84%E5%8D%95%E8%AF%8D.png' width=600> </img></div>
```C++
// 版本一
@ -183,7 +183,7 @@ public:
int end = 0; // 反转的单词在字符串里终止位置
bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
for (int i = 0; i < s.size(); i++) { // 开始反转单词
if ((!entry))) {
if (!entry) {
start = i; // 确定单词起始位置
entry = true; // 进入单词区间
}
@ -203,6 +203,7 @@ public:
return s;
}
// 当然这里的主函数reverseWords写的有一些冗余的可以精简一些精简之后的主函数为
/* 主函数简单写法
string reverseWords(string s) {
removeExtraSpaces(s);
@ -220,25 +221,8 @@ public:
};
```
当然这里的主函数reverseWords写的有一些冗余的可以精简一些精简之后的主函数为
```C++
// 注意这里仅仅是主函数,其他函数和版本一一致
string reverseWords(string s) {
removeExtraSpaces(s);
reverse(s, 0, s.size() - 1);
for(int i = 0; i < s.size(); i++) {
int j = i;
// 查找单词间的空格,翻转单词
while(j < s.size() && s[j] != ' ') j++;
reverse(s, i, j - 1);
i = j;
}
return s;
}
```
效率
<img src='https://code-thinking.cdn.bcebos.com/pics/151_翻转字符串里的单词.png' width=600> </img></div>
@ -316,7 +300,57 @@ class Solution {
}
```
Python
```Python3
class Solution:
#1.去除多余的空格
def trim_spaces(self,s):
n=len(s)
left=0
right=n-1
while left<=right and s[left]==' ': #去除开头的空格
left+=1
while left<=right and s[right]==' ': #去除结尾的空格
right=right-1
tmp=[]
while left<=right: #去除单词中间多余的空格
if s[left]!=' ':
tmp.append(s[left])
elif tmp[-1]!=' ': #当前位置是空格,但是相邻的上一个位置不是空格,则该空格是合理的
tmp.append(s[left])
left+=1
return tmp
#2.翻转字符数组
def reverse_string(self,nums,left,right):
while left<right:
nums[left], nums[right]=nums[right],nums[left]
left+=1
right-=1
return None
#3.翻转每个单词
def reverse_each_word(self, nums):
start=0
end=0
n=len(nums)
while start<n:
while end<n and nums[end]!=' ':
end+=1
self.reverse_string(nums,start,end-1)
start=end+1
end+=1
return None
#4.翻转字符串里的单词
def reverseWords(self, s): #测试用例:"the sky is blue"
l = self.trim_spaces(s) #输出:['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'
self.reverse_string( l, 0, len(l) - 1) #输出:['e', 'u', 'l', 'b', ' ', 's', 'i', ' ', 'y', 'k', 's', ' ', 'e', 'h', 't']
self.reverse_each_word(l) #输出:['b', 'l', 'u', 'e', ' ', 'i', 's', ' ', 's', 'k', 'y', ' ', 't', 'h', 'e']
return ''.join(l) #输出blue is sky the
'''
Go

View File

@ -0,0 +1,2 @@
同:[链表:链表相交](./面试题02.07.链表相交.md)

View File

@ -212,6 +212,20 @@ class Solution { //动态规划
Python
```python
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
if len(prices) == 0:
return 0
dp = [[0] * (2*k+1) for _ in range(len(prices))]
for j in range(1, 2*k, 2):
dp[0][j] = -prices[0]
for i in range(1, len(prices)):
for j in range(0, 2*k-1, 2):
dp[i][j+1] = max(dp[i-1][j+1], dp[i-1][j] - prices[i])
dp[i][j+2] = max(dp[i-1][j+2], dp[i-1][j+1] + prices[i])
return dp[-1][2*k]
```
Go

View File

@ -118,7 +118,7 @@ class Solution {
if (nums == null || nums.length == 0) return 0;
if (nums.length == 1) return nums[0];
int[] dp = new int[nums.length + 1];
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(dp[0], nums[1]);
for (int i = 2; i < nums.length; i++) {
@ -131,7 +131,20 @@ class Solution {
```
Python
```python
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i-2]+nums[i], dp[i-1])
return dp[-1]
```
Go
```Go

View File

@ -118,8 +118,8 @@ public:
## 相关题目推荐
* 904.水果成篮
* 76.最小覆盖子串
* [904.水果成篮](https://leetcode-cn.com/problems/fruit-into-baskets/)
* [76.最小覆盖子串](https://leetcode-cn.com/problems/minimum-window-substring/)

View File

@ -308,6 +308,35 @@ class Solution:
Go
递归版本
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
//本题直接就是求有多少个节点,无脑存进数组算长度就行了。
func countNodes(root *TreeNode) int {
if root == nil {
return 0
}
res := 1
if root.Right != nil {
res += countNodes(root.Right)
}
if root.Left != nil {
res += countNodes(root.Left)
}
return res
}
```
JavaScript:
递归版本

View File

@ -265,6 +265,54 @@ class Solution:
else: return root
```
Go
> BSL法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
//利用BSL的性质前序遍历有序
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root==nil{return nil}
if root.Val>p.Val&&root.Val>q.Val{//当前节点的值大于给定的值,则说明满足条件的在左边
return lowestCommonAncestor(root.Left,p,q)
}else if root.Val<p.Val&&root.Val<q.Val{//当前节点的值小于各点的值,则说明满足条件的在右边
return lowestCommonAncestor(root.Right,p,q)
}else {return root}//当前节点的值在给定值的中间(或者等于),即为最深的祖先
}
```
> 普通法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
//递归会将值层层返回
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
//终止条件
if root==nil||root.Val==p.Val||root.Val==q.Val{return root}//最后为空或者找到一个值时,就返回这个值
//后序遍历
findLeft:=lowestCommonAncestor(root.Left,p,q)
findRight:=lowestCommonAncestor(root.Right,p,q)
//处理单层逻辑
if findLeft!=nil&&findRight!=nil{return root}//说明在root节点的两边
if findLeft==nil{//左边没找到,就说明在右边找到了
return findRight
}else {return findLeft}
}
```

View File

@ -332,6 +332,66 @@ func maxSlidingWindow(nums []int, k int) []int {
```
```go
// 封装单调队列的方式解题
type MyQueue struct {
queue []int
}
func NewMyQueue() *MyQueue {
return &MyQueue{
queue: make([]int, 0),
}
}
func (m *MyQueue) Front() int {
return m.queue[0]
}
func (m *MyQueue) Back() int {
return m.queue[len(m.queue)-1]
}
func (m *MyQueue) Empty() bool {
return len(m.queue) == 0
}
func (m *MyQueue) Push(val int) {
for !m.Empty() && val > m.Back() {
m.queue = m.queue[:len(m.queue)-1]
}
m.queue = append(m.queue, val)
}
func (m *MyQueue) Pop(val int) {
if !m.Empty() && val == m.Front() {
m.queue = m.queue[1:]
}
}
func maxSlidingWindow(nums []int, k int) []int {
queue := NewMyQueue()
length := len(nums)
res := make([]int, 0)
// 先将前k个元素放入队列
for i := 0; i < k; i++ {
queue.Push(nums[i])
}
// 记录前k个元素的最大值
res = append(res, queue.Front())
for i := k; i < length; i++ {
// 滑动窗口移除最前面的元素
queue.Pop(nums[i-k])
// 滑动窗口添加最后面的元素
queue.Push(nums[i])
// 记录最大值
res = append(res, queue.Front())
}
return res
}
```
Javascript:
```javascript
var maxSlidingWindow = function (nums, k) {

View File

@ -130,7 +130,27 @@ class Solution:
return True
```
Python写法二没有使用数组作为哈希表只是介绍defaultdict这样一种解题思路
```python
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
from collections import defaultdict
s_dict = defaultdict(int)
t_dict = defaultdict(int)
for x in s:
s_dict[x] += 1
for x in t:
t_dict[x] += 1
return s_dict == t_dict
```
Go
```go
func isAnagram(s string, t string) bool {
if len(s)!=len(t){

View File

@ -26,7 +26,7 @@
输入n = 13
输出2
解释13 = 4 + 9
 
提示:
* 1 <= n <= 10^4
@ -184,9 +184,89 @@ class Solution {
Python
```python3
class Solution:
def numSquares(self, n: int) -> int:
'''版本一'''
# 初始化
nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
dp = [10**4]*(n + 1)
dp[0] = 0
# 遍历背包
for j in range(1, n + 1):
# 遍历物品
for num in nums:
if j >= num:
dp[j] = min(dp[j], dp[j - num] + 1)
return dp[n]
def numSquares1(self, n: int) -> int:
'''版本二'''
# 初始化
nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
dp = [10**4]*(n + 1)
dp[0] = 0
# 遍历物品
for num in nums:
# 遍历背包
for j in range(num, n + 1)
dp[j] = min(dp[j], dp[j - num] + 1)
return dp[n]
```
Go
```go
// 版本一,先遍历物品, 再遍历背包
func numSquares1(n int) int {
//定义
dp := make([]int, n+1)
// 初始化
dp[0] = 0
for i := 1; i <= n; i++ {
dp[i] = math.MaxInt32
}
// 遍历物品
for i := 1; i <= n; i++ {
// 遍历背包
for j := i*i; j <= n; j++ {
dp[j] = min(dp[j], dp[j-i*i]+1)
}
}
return dp[n]
}
// 版本二,先遍历背包, 再遍历物品
func numSquares2(n int) int {
//定义
dp := make([]int, n+1)
// 初始化
dp[0] = 0
// 遍历背包
for j := 1; j <= n; j++ {
//初始化
dp[j] = math.MaxInt32
// 遍历物品
for i := 1; i <= n; i++ {
if j >= i*i {
dp[j] = min(dp[j], dp[j-i*i]+1)
}
}
}
return dp[n]
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
```

View File

@ -130,7 +130,20 @@ class Solution {
```
Python
```python
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if len(nums) <= 1:
return len(nums)
dp = [1] * len(nums)
result = 0
for i in range(1, len(nums)):
for j in range(0, i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j] + 1)
result = max(result, dp[i]) #取长的子序列
return result
```
Go
```go

View File

@ -189,6 +189,21 @@ class Solution {
Python
```python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
if n == 0:
return 0
dp = [[0] * 4 for _ in range(n)]
dp[0][0] = -prices[0] #持股票
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], max(dp[i-1][3], dp[i-1][1]) - prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][3])
dp[i][2] = dp[i-1][0] + prices[i]
dp[i][3] = dp[i-1][2]
return max(dp[n-1][3], dp[n-1][1], dp[n-1][2])
```
Go

View File

@ -35,7 +35,7 @@
示例 5
输入coins = [1], amount = 2
输出2
 
提示:
* 1 <= coins.length <= 12
@ -209,9 +209,100 @@ class Solution {
Python
```python3
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
'''版本一'''
# 初始化
dp = [amount + 1]*(amount + 1)
dp[0] = 0
# 遍历物品
for coin in coins:
# 遍历背包
for j in range(coin, amount + 1):
dp[j] = min(dp[j], dp[j - coin] + 1)
return dp[amount] if dp[amount] < amount + 1 else -1
def coinChange1(self, coins: List[int], amount: int) -> int:
'''版本二'''
# 初始化
dp = [amount + 1]*(amount + 1)
dp[0] = 0
# 遍历物品
for j in range(1, amount + 1):
# 遍历背包
for coin in coins:
if j >= coin:
dp[j] = min(dp[j], dp[j - coin] + 1)
return dp[amount] if dp[amount] < amount + 1 else -1
```
Go
```go
// 版本一, 先遍历物品,再遍历背包
func coinChange1(coins []int, amount int) int {
dp := make([]int, amount+1)
// 初始化dp[0]
dp[0] = 0
// 初始化为math.MaxInt32
for j := 1; j <= amount; j++ {
dp[j] = math.MaxInt32
}
// 遍历物品
for i := 0; i < len(coins); i++ {
// 遍历背包
for j := coins[i]; j <= amount; j++ {
if dp[j-coins[i]] != math.MaxInt32 {
// 推导公式
dp[j] = min(dp[j], dp[j-coins[i]]+1)
//fmt.Println(dp,j,i)
}
}
}
// 没找到能装满背包的, 就返回-1
if dp[amount] == math.MaxInt32 {
return -1
}
return dp[amount]
}
// 版本二,先遍历背包,再遍历物品
func coinChange2(coins []int, amount int) int {
dp := make([]int, amount+1)
// 初始化dp[0]
dp[0] = 0
// 遍历背包,从1开始
for j := 1; j <= amount; j++ {
// 初始化为math.MaxInt32
dp[j] = math.MaxInt32
// 遍历物品
for i := 0; i < len(coins); i++ {
if j >= coins[i] && dp[j-coins[i]] != math.MaxInt32 {
// 推导公式
dp[j] = min(dp[j], dp[j-coins[i]]+1)
//fmt.Println(dp)
}
}
}
// 没找到能装满背包的, 就返回-1
if dp[amount] == math.MaxInt32 {
return -1
}
return dp[amount]
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
```

View File

@ -287,6 +287,25 @@ class Solution {
Python
> 动态规划
```python
class Solution:
def rob(self, root: TreeNode) -> int:
result = self.robTree(root)
return max(result[0], result[1])
#长度为2的数组0不偷1
def robTree(self, cur):
if not cur:
return (0, 0) #这里返回tuple, 也可以返回list
left = self.robTree(cur.left)
right = self.robTree(cur.right)
#偷cur
val1 = cur.val + left[0] + right[0]
#不偷cur
val2 = max(left[0], left[1]) + max(right[0], right[1])
return (val2, val1)
```
Go

View File

@ -218,7 +218,7 @@ class Solution:
# 假设对正整数 i 拆分出的第一个正整数是 j1 <= j < i则有以下两种方案
# 1) 将 i 拆分成 j 和 ij 的和,且 ij 不再拆分成多个正整数,此时的乘积是 j * (i-j)
# 2) 将 i 拆分成 j 和 ij 的和,且 ij 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
for j in range(1, i):
for j in range(1, i - 1):
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
return dp[n]
```

View File

@ -21,11 +21,10 @@ https://leetcode-cn.com/problems/reverse-string/
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2
示例 2
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
@ -56,7 +55,7 @@ https://leetcode-cn.com/problems/reverse-string/
接下来再来讲一下如何解决反转字符串的问题。
大家应该还记得,我们已经讲过了[206.反转链表](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)。
大家应该还记得,我们已经讲过了[206.反转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)。
在反转链表中,使用了双指针的方法。
@ -64,7 +63,7 @@ https://leetcode-cn.com/problems/reverse-string/
因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。
如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/ntlZbEdKgnFQKZkSUAOSpQ)[必须掌握的数组理论知识](https://mp.weixin.qq.com/s/X7R55wSENyY62le0Fiawsg)。
如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)[必须掌握的数组理论知识](https://mp.weixin.qq.com/s/c2KABb-Qgg66HrGf8z-8Og)。
对于字符串,我们定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。
@ -119,8 +118,7 @@ s[i] ^= s[j];
相信大家本着我所讲述的原则来做字符串相关的题目,在选择库函数的角度上会有所原则,也会有所收获。
## C++代码
C++代码如下:
```C++
class Solution {

View File

@ -118,7 +118,7 @@ class Solution {
```
Python
```python3
```python
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
result_set = set()

View File

@ -138,20 +138,16 @@ class Solution {
```
Python
```python
```python3
class Solution:
def wiggleMaxLength(self, nums: List[int]) -> int:
#贪心 求波峰数量 + 波谷数量
if len(nums)<=1:
return len(nums)
cur, pre = 0,0 #当前一对差值,前一对差值
count = 1#默认最右边有一个峰值
preC,curC,res = 0,0,1 #题目里nums长度大于等于1当长度为1时其实到不了for循环里去所以不用考虑nums长度
for i in range(len(nums) - 1):
cur = nums[i+1] - nums[i]
if((cur>0 and pre<=0) or (cur<0 and pre>=0)):
count += 1
pre = cur
return count
curC = nums[i + 1] - nums[i]
if curC * preC <= 0 and curC !=0: #差值为0时不算摆动
res += 1
preC = curC #如果当前差值和上一个差值为一正一负时,才需要用当前差值替代上一个差值
return res
```
Go

View File

@ -183,7 +183,23 @@ class Solution:
Go
```go
func combinationSum4(nums []int, target int) int {
//定义dp数组
dp := make([]int, target+1)
// 初始化
dp[0] = 1
// 遍历顺序, 先遍历背包,再循环遍历物品
for j:=0;j<=target;j++ {
for i:=0 ;i < len(nums);i++ {
if j >= nums[i] {
dp[j] += dp[j-nums[i]]
}
}
}
return dp[target]
}
```

View File

@ -28,7 +28,7 @@ canConstruct("aa", "aab") -> true
## 思路
这道题目和[242.有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b而不用管字符串b 能不能组成字符串a。
这道题目和[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b而不用管字符串b 能不能组成字符串a。
本题判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成但是这里需要注意两点。
@ -75,7 +75,7 @@ public:
依然是数组在哈希法中的应用。
一些同学可能想用数组干啥都用map完事了**其实在本题的情况下使用map的空间消耗要比数组大一些的因为map要维护红黑树或者哈希表而且还要做哈希函数。 所以数组更加简单直接有效!**
一些同学可能想用数组干啥都用map完事了**其实在本题的情况下使用map的空间消耗要比数组大一些的因为map要维护红黑树或者哈希表而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!**
代码如下:
@ -135,8 +135,52 @@ class Solution {
```
Python
```py
Python写法一(使用数组作为哈希表)
```python
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
arr = [0] * 26
for x in magazine:
arr[ord(x) - ord('a')] += 1
for x in ransomNote:
if arr[ord(x) - ord('a')] == 0:
return False
else:
arr[ord(x) - ord('a')] -= 1
return True
```
Python写法二使用defaultdict
```python
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
from collections import defaultdict
hashmap = defaultdict(int)
for x in magazine:
hashmap[x] += 1
for x in ransomNote:
value = hashmap.get(x)
if value is None or value == 0:
return False
else:
hashmap[x] -= 1
return True
```
Python写法三
```python
class Solution(object):
def canConstruct(self, ransomNote, magazine):
"""
@ -166,6 +210,7 @@ class Solution(object):
```
Go
```go
func canConstruct(ransomNote string, magazine string) bool {
record := make([]int, 26)

View File

@ -144,7 +144,20 @@ Java
Python
```python
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
dp = [[0] * (len(t)+1) for _ in range(len(s)+1)]
for i in range(1, len(s)+1):
for j in range(1, len(t)+1):
if s[i-1] == t[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = dp[i][j-1]
if dp[-1][-1] == len(s):
return True
return False
```
Go

View File

@ -226,6 +226,71 @@ class Solution:
```
Go
> 递归法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func sumOfLeftLeaves(root *TreeNode) int {
var res int
findLeft(root,&res)
return res
}
func findLeft(root *TreeNode,res *int){
//左节点
if root.Left!=nil&&root.Left.Left==nil&&root.Left.Right==nil{
*res=*res+root.Left.Val
}
if root.Left!=nil{
findLeft(root.Left,res)
}
if root.Right!=nil{
findLeft(root.Right,res)
}
}
```
> 迭代法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func sumOfLeftLeaves(root *TreeNode) int {
var res int
queue:=list.New()
queue.PushBack(root)
for queue.Len()>0{
length:=queue.Len()
for i:=0;i<length;i++{
node:=queue.Remove(queue.Front()).(*TreeNode)
if node.Left!=nil&&node.Left.Left==nil&&node.Left.Right==nil{
res=res+node.Left.Val
}
if node.Left!=nil{
queue.PushBack(node.Left)
}
if node.Right!=nil{
queue.PushBack(node.Right)
}
}
}
return res
}
```
JavaScript:
递归版本
```javascript
@ -275,6 +340,7 @@ var sumOfLeftLeaves = function(root) {
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -226,7 +226,25 @@ class Solution:
Go
Javascript:
```Javascript
var reconstructQueue = function(people) {
let queue = []
people.sort((a, b ) => {
if(b[0] !== a[0]) {
return b[0] - a[0]
} else {
return a[1] - b[1]
}
})
for(let i = 0; i < people.length; i++) {
queue.splice(people[i][1], 0, people[i])
}
return queue
};
```
-----------------------

View File

@ -228,7 +228,27 @@ class Solution:
Go
Javascript:
```Javascript
var eraseOverlapIntervals = function(intervals) {
intervals.sort((a, b) => {
return a[1] - b[1]
})
let count = 1
let end = intervals[0][1]
for(let i = 1; i < intervals.length; i++) {
let interval = intervals[i]
if(interval[0] >= right) {
end = interval[1]
count += 1
}
}
return intervals.length - count
};
```
-----------------------

View File

@ -175,7 +175,24 @@ class Solution:
Go
Javascript:
```Javascript
var findMinArrowShots = function(points) {
points.sort((a, b) => {
return a[0] - b[0]
})
let result = 1
for(let i = 1; i < points.length; i++) {
if(points[i][0] > points[i - 1][1]) {
result++
} else {
points[i][1] = Math.min(points[i - 1][1], points[i][1])
}
}
return result
};
```
-----------------------

View File

@ -120,7 +120,7 @@ class Solution {
Python
```
```python
class Solution(object):
def fourSumCount(self, nums1, nums2, nums3, nums4):
"""
@ -148,6 +148,30 @@ class Solution(object):
count += hashmap[key]
return count
# 下面这个写法更为简洁,但是表达的是同样的算法
# class Solution:
# def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
# from collections import defaultdict
# hashmap = defaultdict(int)
# for x1 in nums1:
# for x2 in nums2:
# hashmap[x1+x2] += 1
# count=0
# for x3 in nums3:
# for x4 in nums4:
# key = -x3-x4
# value = hashmap.get(key)
# dict的get方法会返回Nonekey不存在或者key对应的value
# 所以如果value==0就会继续执行orcount+0否则就会直接加value
# 这样就不用去写if判断了
# count += value or 0
# return count
```

View File

@ -134,22 +134,17 @@ class Solution {
```
Python
```python
```python3
class Solution:
def findContentChildren(self, g: List[int], s: List[int]) -> int:
#先考虑胃口小的孩子
g.sort()
s.sort()
i=j=0
count = 0
while(i<len(g) and j<len(s)):
if g[i]<=s[j]:
count+=1
i+=1 #如果满足了,则继续遍历下一个孩子和下一块饼干
j += 1 #如果最小的饼干没有满足当前最小胃口的孩子,则遍历下一块饼干
return count
res = 0
for i in range(len(s)):
if res <len(g) and s[i] >= g[res]: #小饼干先喂饱小胃口
res += 1
return res
```
Go
Javascript:

View File

@ -206,7 +206,43 @@ class Solution:
```
Go
```go
func findMaxForm(strs []string, m int, n int) int {
// 定义数组
dp := make([][]int, m+1)
for i,_ := range dp {
dp[i] = make([]int, n+1 )
}
// 遍历
for i:=0;i<len(strs);i++ {
zeroNum,oneNum := 0 , 0
//计算0,1 个数
//或者直接strings.Count(strs[i],"0")
for _,v := range strs[i] {
if v == '0' {
zeroNum++
}
}
oneNum = len(strs[i])-zeroNum
// 从后往前 遍历背包容量
for j:= m ; j >= zeroNum;j-- {
for k:=n ; k >= oneNum;k-- {
// 推导公式
dp[j][k] = max(dp[j][k],dp[j-zeroNum][k-oneNum]+1)
}
}
//fmt.Println(dp)
}
return dp[m][n]
}
func max(a,b int) int {
if a > b {
return a
}
return b
}
```

View File

@ -428,7 +428,100 @@ class Solution:
return self.res
```
Go
暴力法非BSL
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func findMode(root *TreeNode) []int {
var history map[int]int
var maxValue int
var maxIndex int
var result []int
history=make(map[int]int)
traversal(root,history)
for k,value:=range history{
if value>maxValue{
maxValue=value
maxIndex=k
}
}
for k,value:=range history{
if value==history[maxIndex]{
result=append(result,k)
}
}
return result
}
func traversal(root *TreeNode,history map[int]int){
if root.Left!=nil{
traversal(root.Left,history)
}
if value,ok:=history[root.Val];ok{
history[root.Val]=value+1
}else{
history[root.Val]=1
}
if root.Right!=nil{
traversal(root.Right,history)
}
}
```
计数法BSL此代码在执行代码里能执行但提交后报错不知为何思路是对的
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
var count,maxCount int //统计计数
func findMode(root *TreeNode) []int {
var result []int
var pre *TreeNode //前指针
if root.Left==nil&&root.Right==nil{
result=append(result,root.Val)
return result
}
traversal(root,&result,pre)
return result
}
func traversal(root *TreeNode,result *[]int,pre *TreeNode){//遍历统计
//如果BSL中序遍历相邻的两个节点值相同则统计频率如果不相同依据BSL中序遍历排好序的性质重新计数
if pre==nil{
count=1
}else if pre.Val==root.Val{
count++
}else {
count=1
}
//如果统计的频率等于最大频率,则加入结果集;如果统计的频率大于最大频率,更新最大频率且重新将结果加入新的结果集中
if count==maxCount{
*result=append(*result,root.Val)
}else if count>maxCount{
maxCount=count//重新赋值maxCount
*result=[]int{}//清空result中的内容
*result=append(*result,root.Val)
}
pre=root//保存上一个的节点
if root.Left!=nil{
traversal(root.Left,result,pre)
}
if root.Right!=nil{
traversal(root.Right,result,pre)
}
}
```

View File

@ -298,6 +298,80 @@ class Solution:
```
Go
> 递归法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
var maxDeep int // 全局变量 深度
var value int //全局变量 最终值
func findBottomLeftValue(root *TreeNode) int {
if root.Left==nil&&root.Right==nil{//需要提前判断一下不要这个if的话提交结果会出错但执行代码不会。防止这种情况出现故先判断是否只有一个节点
return root.Val
}
findLeftValue (root,maxDeep)
return value
}
func findLeftValue (root *TreeNode,deep int){
//最左边的值在左边
if root.Left==nil&&root.Right==nil{
if deep>maxDeep{
value=root.Val
maxDeep=deep
}
}
//递归
if root.Left!=nil{
deep++
findLeftValue(root.Left,deep)
deep--//回溯
}
if root.Right!=nil{
deep++
findLeftValue(root.Right,deep)
deep--//回溯
}
}
```
> 迭代法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func findBottomLeftValue(root *TreeNode) int {
queue:=list.New()
var gradation int
queue.PushBack(root)
for queue.Len()>0{
length:=queue.Len()
for i:=0;i<length;i++{
node:=queue.Remove(queue.Front()).(*TreeNode)
if i==0{gradation=node.Val}
if node.Left!=nil{
queue.PushBack(node.Left)
}
if node.Right!=nil{
queue.PushBack(node.Right)
}
}
}
return gradation
}
```
JavaScript:
1. 递归版本
```javascript

View File

@ -170,7 +170,20 @@ public class Solution {
Python
```python
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
dp = [[0] * len(s) for _ in range(len(s))]
for i in range(len(s)):
dp[i][i] = 1
for i in range(len(s)-1, -1, -1):
for j in range(i+1, len(s)):
if s[i] == s[j]:
dp[i][j] = dp[i+1][j-1] + 2
else:
dp[i][j] = max(dp[i+1][j], dp[i][j-1])
return dp[0][-1]
```
Go
```Go

View File

@ -33,7 +33,7 @@
示例 3:
输入: amount = 10, coins = [10]
输出: 1
 
注意,你可以假设:
* 0 <= amount (总金额) <= 5000
@ -101,7 +101,7 @@ dp[j] 考虑coins[i]的组合总和) 就是所有的dp[j - coins[i]](不
而本题要求凑成总和的组合数,元素之间要求没有顺序。
所以纯完全背包是能凑成总就行,不用管怎么凑的。
所以纯完全背包是能凑成总就行,不用管怎么凑的。
本题是求凑出来的方案个数,且每个方案个数是为组合数。
@ -208,10 +208,42 @@ class Solution {
Python
Go
```python3
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0]*(amount + 1)
dp[0] = 1
# 遍历物品
for i in range(len(coins)):
# 遍历背包
for j in range(coins[i], amount + 1):
dp[j] += dp[j - coins[i]]
return dp[amount]
```
Go
```go
func change(amount int, coins []int) int {
// 定义dp数组
dp := make([]int, amount+1)
// 初始化,0大小的背包, 当然是不装任何东西了, 就是1种方法
dp[0] = 1
// 遍历顺序
// 遍历物品
for i := 0 ;i < len(coins);i++ {
// 遍历背包
for j:= coins[i] ; j <= amount ;j++ {
// 推导公式
dp[j] += dp[j-coins[i]]
}
}
return dp[amount]
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -151,7 +151,30 @@ public:
Java
递归
```java
class Solution {
TreeNode pre;// 记录上一个遍历的结点
int result = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
if(root==null)return 0;
traversal(root);
return result;
}
public void traversal(TreeNode root){
if(root==null)return;
//左
traversal(root.left);
//中
if(pre!=null){
result = Math.min(result,root.val-pre.val);
}
pre = root;
//右
traversal(root.right);
}
}
```
```Java
class Solution {
TreeNode pre;// 记录上一个遍历的结点
@ -201,8 +224,37 @@ class Solution:
return r
```
Go
> 中序遍历,然后计算最小差值
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func getMinimumDifference(root *TreeNode) int {
var res []int
findMIn(root,&res)
min:=1000000//一个比较大的值
for i:=1;i<len(res);i++{
tempValue:=res[i]-res[i-1]
if tempValue<min{
min=tempValue
}
}
return min
}
//中序遍历
func findMIn(root *TreeNode,res *[]int){
if root==nil{return}
findMIn(root.Left,res)
*res=append(*res,root.Val)
findMIn(root.Right,res)
}
```
-----------------------

View File

@ -38,7 +38,7 @@ https://leetcode-cn.com/problems/reverse-string-ii/
**所以当需要固定规律一段一段去处理字符串的时候要想想在在for循环的表达式上做做文章。**
性能如下:
<img src='https://code-thinking.cdn.bcebos.com/pics/541_%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2II.png' width=600> </img></div>
<img src='https://code-thinking.cdn.bcebos.com/pics/541_反转字符串II.png' width=600> </img></div>
那么这里具体反转的逻辑我们要不要使用库函数呢其实用不用都可以使用reverse来实现反转也没毛病毕竟不是解题关键部分。
@ -65,7 +65,7 @@ public:
};
```
那么我们也可以实现自己的reverse函数其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA)道理是一样的。
那么我们也可以实现自己的reverse函数其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)道理是一样的。
下面我实现的reverse函数区间是左闭右闭区间代码如下
@ -103,6 +103,7 @@ public:
Java
```Java
//解法一
class Solution {
public String reverseStr(String s, int k) {
StringBuffer res = new StringBuffer();
@ -128,6 +129,28 @@ class Solution {
return res.toString();
}
}
//解法二(似乎更容易理解点)
//题目的意思其实概括为 每隔2k个反转前k个尾数不够k个时候全部反转
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for(int i = 0; i < ch.length; i += 2 * k){
int start = i;
//这里是判断尾数够不够k个来取决end指针的位置
int end = Math.min(ch.length - 1, start + k - 1);
//用异或运算反转
while(start < end){
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end--;
}
}
return new String(ch);
}
}
```
Python

View File

@ -104,10 +104,47 @@ public:
Java
```java
class Solution {
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
for (int i = 0; i < word1.length() + 1; i++) dp[i][0] = i;
for (int j = 0; j < word2.length() + 1; j++) dp[0][j] = j;
for (int i = 1; i < word1.length() + 1; i++) {
for (int j = 1; j < word2.length() + 1; j++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
}else{
dp[i][j] = Math.min(dp[i - 1][j - 1] + 2,
Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
}
}
}
return dp[word1.length()][word2.length()];
}
}
```
Python
```python
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
dp = [[0] * (len(word2)+1) for _ in range(len(word1)+1)]
for i in range(len(word1)+1):
dp[i][0] = i
for j in range(len(word2)+1):
dp[0][j] = j
for i in range(1, len(word1)+1):
for j in range(1, len(word2)+1):
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = min(dp[i-1][j-1] + 2, dp[i-1][j] + 1, dp[i][j-1] + 1)
return dp[-1][-1]
```
Go

View File

@ -332,6 +332,43 @@ class Solution:
Go
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
//前序遍历递归遍历跟105 106差不多的思路
func mergeTrees(t1 *TreeNode, t2 *TreeNode) *TreeNode {
var value int
var nullNode *TreeNode//空node便于遍历
nullNode=&TreeNode{
Val:0,
Left:nil,
Right:nil}
switch {
case t1==nil&&t2==nil: return nil//终止条件
default : //如果其中一个节点为空则将该节点置为nullNode方便下次遍历
if t1==nil{
value=t2.Val
t1=nullNode
}else if t2==nil{
value=t1.Val
t2=nullNode
}else {
value=t1.Val+t2.Val
}
}
root:=&TreeNode{//构造新的二叉树
Val: value,
Left: mergeTrees(t1.Left,t2.Left),
Right: mergeTrees(t1.Right,t2.Right)}
return root
}
```

View File

@ -284,6 +284,56 @@ class Solution {
Python
> 动态规划:
```python
class Solution:
def countSubstrings(self, s: str) -> int:
dp = [[False] * len(s) for _ in range(len(s))]
result = 0
for i in range(len(s)-1, -1, -1): #注意遍历顺序
for j in range(i, len(s)):
if s[i] == s[j]:
if j - i <= 1: #情况一 和 情况二
result += 1
dp[i][j] = True
elif dp[i+1][j-1]: #情况三
result += 1
dp[i][j] = True
return result
```
> 动态规划:简洁版
```python
class Solution:
def countSubstrings(self, s: str) -> int:
dp = [[False] * len(s) for _ in range(len(s))]
result = 0
for i in range(len(s)-1, -1, -1): #注意遍历顺序
for j in range(i, len(s)):
if s[i] == s[j] and (j - i <= 1 or dp[i+1][j-1]):
result += 1
dp[i][j] = True
return result
```
> 双指针法:
```python
class Solution:
def countSubstrings(self, s: str) -> int:
result = 0
for i in range(len(s)):
result += self.extend(s, i, i, len(s)) #以i为中心
result += self.extend(s, i, i+1, len(s)) #以i和i+1为中心
return result
def extend(self, s, i, j, n):
res = 0
while i >= 0 and j < n and s[i] == s[j]:
i -= 1
j += 1
res += 1
return res
```
Go
```Go

View File

@ -278,6 +278,75 @@ class Solution:
Go
> 654. 最大二叉树
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func constructMaximumBinaryTree(nums []int) *TreeNode {
if len(nums)<1{return nil}
//首选找到最大值
index:=findMax(nums)
//其次构造二叉树
root:=&TreeNode{
Val: nums[index],
Left:constructMaximumBinaryTree(nums[:index]),//左半边
Right:constructMaximumBinaryTree(nums[index+1:]),//右半边
}
return root
}
func findMax(nums []int) (index int){
for i:=0;i<len(nums);i++{
if nums[i]>nums[index]{
index=i
}
}
return
}
```
JavaScript版本
```javascript
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} nums
* @return {TreeNode}
*/
var constructMaximumBinaryTree = function (nums) {
const BuildTree = (arr, left, right) => {
if (left > right)
return null;
let maxValue = -1;
let maxIndex = -1;
for (let i = left; i <= right; ++i) {
if (arr[i] > maxValue) {
maxValue = arr[i];
maxIndex = i;
}
}
let root = new TreeNode(maxValue);
root.left = BuildTree(arr, left, maxIndex - 1);
root.right = BuildTree(arr, maxIndex + 1, right);
return root;
}
let root = BuildTree(nums, 0, nums.length - 1);
return root;
};
```

View File

@ -156,10 +156,65 @@ public:
Java
```java
/**
* 1.dp[i] 代表当前下表最大连续值
* 2.递推公式 ifnums[i+1]>nums[i] dp[i+1] = dp[i]+1
* 3.初始化 都为1
* 4.遍历方向,从其那往后
* 5.结果推导 。。。。
* @param nums
* @return
*/
public static int findLengthOfLCIS(int[] nums) {
int[] dp = new int[nums.length];
for (int i = 0; i < dp.length; i++) {
dp[i] = 1;
}
int res = 1;
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] > nums[i]) {
dp[i + 1] = dp[i] + 1;
}
res = res > dp[i + 1] ? res : dp[i + 1];
}
return res;
}
```
Python
> 动态规划:
```python
class Solution:
def findLengthOfLCIS(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
result = 1
dp = [1] * len(nums)
for i in range(len(nums)-1):
if nums[i+1] > nums[i]: #连续记录
dp[i+1] = dp[i] + 1
result = max(result, dp[i+1])
return result
```
> 贪心法:
```python
class Solution:
def findLengthOfLCIS(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
result = 1 #连续子序列最少也是1
count = 1
for i in range(len(nums)-1):
if nums[i+1] > nums[i]: #连续记录
count += 1
else: #不连续count从头开始
count = 1
result = max(result, count)
return result
```
Go

View File

@ -241,6 +241,56 @@ class Solution:
Go
> 递归法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
//递归法
func searchBST(root *TreeNode, val int) *TreeNode {
if root==nil||root.Val==val{
return root
}
if root.Val>val{
return searchBST(root.Left,val)
}
return searchBST(root.Right,val)
}
```
> 迭代法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
//迭代法
func searchBST(root *TreeNode, val int) *TreeNode {
for root!=nil{
if root.Val>val{
root=root.Left
}else if root.Val<val{
root=root.Right
}else{
break
}
}
return root
}
```

View File

@ -13,16 +13,21 @@
给定一个 n 个元素有序的升序整型数组 nums 和一个目标值 target  写一个函数搜索 nums 中的 target如果目标值存在返回下标否则返回 -1。
示例 1:
```
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
```
示例 2:
```
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
```
提示:
@ -146,7 +151,7 @@ public:
## 其他语言版本
Java
**Java**
(版本一)左闭右闭区间
@ -192,9 +197,11 @@ class Solution {
}
```
Python
**Python**
```python3
(版本一)左闭右闭区间
```python
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
@ -211,8 +218,26 @@ class Solution:
return -1
```
(版本二)左闭右开区间
Go
```python
class Solution:
def search(self, nums: List[int], target: int) -> int:
left,right =0, len(nums)
while left < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid+1
elif nums[mid] > target:
right = mid
else:
return mid
return -1
```
**Go**
(版本一)左闭右闭区间
@ -254,7 +279,7 @@ func search(nums []int, target int) int {
}
```
javaScript
**javaScript:**
```js

View File

@ -158,6 +158,7 @@ private:
Java
```Java
//单链表
class ListNode {
int val;
ListNode next;
@ -236,10 +237,110 @@ class MyLinkedList {
pred.next = pred.next.next;
}
}
//双链表
class MyLinkedList {
class ListNode {
int val;
ListNode next,prev;
ListNode(int x) {val = x;}
}
int size;
ListNode head,tail;//Sentinel node
/** Initialize your data structure here. */
public MyLinkedList() {
size = 0;
head = new ListNode(0);
tail = new ListNode(0);
head.next = tail;
tail.prev = head;
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
public int get(int index) {
if(index < 0 || index >= size){return -1;}
ListNode cur = head;
// 通过判断 index < (size - 1) / 2 来决定是从头结点还是尾节点遍历,提高效率
if(index < (size - 1) / 2){
for(int i = 0; i <= index; i++){
cur = cur.next;
}
}else{
cur = tail;
for(int i = 0; i <= size - index - 1; i++){
cur = cur.prev;
}
}
return cur.val;
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
public void addAtHead(int val) {
ListNode cur = head;
ListNode newNode = new ListNode(val);
newNode.next = cur.next;
cur.next.prev = newNode;
cur.next = newNode;
newNode.prev = cur;
size++;
}
/** Append a node of value val to the last element of the linked list. */
public void addAtTail(int val) {
ListNode cur = tail;
ListNode newNode = new ListNode(val);
newNode.next = tail;
newNode.prev = cur.prev;
cur.prev.next = newNode;
cur.prev = newNode;
size++;
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
public void addAtIndex(int index, int val) {
if(index > size){return;}
if(index < 0){index = 0;}
ListNode cur = head;
for(int i = 0; i < index; i++){
cur = cur.next;
}
ListNode newNode = new ListNode(val);
newNode.next = cur.next;
cur.next.prev = newNode;
newNode.prev = cur;
cur.next = newNode;
size++;
}
/** Delete the index-th node in the linked list, if the index is valid. */
public void deleteAtIndex(int index) {
if(index >= size || index < 0){return;}
ListNode cur = head;
for(int i = 0; i < index; i++){
cur = cur.next;
}
cur.next.next.prev = cur;
cur.next = cur.next.next;
size--;
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
```
Python
```python3
```python
# 单链表
class Node:

View File

@ -217,7 +217,29 @@ class Solution: # 贪心思路
Go
Javascript:
```Javascript
// 贪心思路
var maxProfit = function(prices, fee) {
let result = 0
let minPrice = prices[0]
for(let i = 1; i < prices.length; i++) {
if(prices[i] < minPrice) {
minPrice = prices[i]
}
if(prices[i] >= minPrice && prices[i] <= minPrice + fee) {
continue
}
if(prices[i] > minPrice + fee) {
result += prices[i] - minPrice - fee
// 买入和卖出只需要支付一次手续费
minPrice = prices[i] -fee
}
}
return result
};
```
-----------------------

View File

@ -139,7 +139,17 @@ public int maxProfit(int[] prices, int fee) {
```
Python
```python
class Solution:
def maxProfit(self, prices: List[int], fee: int) -> int:
n = len(prices)
dp = [[0] * 2 for _ in range(n)]
dp[0][0] = -prices[0] #持股票
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i] - fee)
return max(dp[-1][0], dp[-1][1])
```
Go

View File

@ -154,10 +154,58 @@ public:
Java
```java
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int result = 0;
int[][] dp = new int[nums1.length + 1][nums2.length + 1];
for (int i = 1; i < nums1.length + 1; i++) {
for (int j = 1; j < nums2.length + 1; j++) {
if (nums1[i - 1] == nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
max = Math.max(max, dp[i][j]);
}
}
}
return result;
}
}
```
Python
> 动态规划:
```python
class Solution:
def findLength(self, A: List[int], B: List[int]) -> int:
dp = [[0] * (len(B)+1) for _ in range(len(A)+1)]
result = 0
for i in range(1, len(A)+1):
for j in range(1, len(B)+1):
if A[i-1] == B[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
result = max(result, dp[i][j])
return result
```
> 动态规划:滚动数组
```python
class Solution:
def findLength(self, A: List[int], B: List[int]) -> int:
dp = [0] * (len(B) + 1)
result = 0
for i in range(1, len(A)+1):
for j in range(len(B), 0, -1):
if A[i-1] == B[j-1]:
dp[j] = dp[j-1] + 1
else:
dp[j] = 0 #注意这里不相等的时候要有赋0的操作
result = max(result, dp[j])
return result
```
Go
```Go

View File

@ -147,23 +147,43 @@ class Solution {
Python
```python
```python3
class Solution:
def monotoneIncreasingDigits(self, n: int) -> int:
strNum = list(str(n))
flag = len(strNum)
for i in range(len(strNum) - 1, 0, -1):
if int(strNum[i]) < int(strNum[i - 1]):
strNum[i - 1] = str(int(strNum[i - 1]) - 1)
flag = i
for i in range(flag, len(strNum)):
strNum[i] = '9'
return int("".join(strNum))
a = list(str(n))
for i in range(len(a)-1,0,-1):
if int(a[i]) < int(a[i-1]):
a[i-1] = str(int(a[i-1]) - 1)
a[i:] = '9' * (len(a) - i) #python不需要设置flag值直接按长度给9就好了
return int("".join(a))
```
Go
Javascript:
```Javascript
var monotoneIncreasingDigits = function(n) {
n = n.toString()
n = n.split('').map(item => {
return +item
})
let flag = Infinity
for(let i = n.length - 1; i > 0; i--) {
if(n [i - 1] > n[i]) {
flag = i
n[i - 1] = n[i - 1] - 1
n[i] = 9
}
}
for(let i = flag; i < n.length; i++) {
n[i] = 9
}
n = n.join('')
return +n
};
```
-----------------------

View File

@ -0,0 +1,271 @@
<p align="center">
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
</p>
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 739. 每日温度
https://leetcode-cn.com/problems/daily-temperatures/
请根据每日 气温 列表重新生成一个列表。对应位置的输出为要想观测到更高的气温至少需要等待的天数。如果气温在这之后都不会升高请在该位置用 0 来代替。
例如给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
## 思路
首先想到的当然是暴力解法两层for循环把至少需要等待的天数就搜出来了。时间复杂度是O(n^2)
那么接下来在来看看使用单调栈的解法。
那有同学就问了,我怎么能想到用单调栈呢? 什么时候用单调栈呢?
**通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了**
时间复杂度为O(n)。
例如本题其实就是找找到一个元素右边第一个比自己大的元素。
此时就应该想到用单调栈了。
那么单调栈的原理是什么呢为什么时间复杂度是O(n)就可以找到每一个元素的右边第一个比它大的元素位置呢?
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素的元素,优点是只需要遍历一次。
在使用单调栈的时候首先要明确如下几点:
1. 单调栈里存放的元素是什么?
单调栈里只需要存放元素的下标i就可以了如果需要使用对应的元素直接T[i]就可以获取。
2. 单调栈里元素是递增呢? 还是递减呢?
**注意一下顺序为 从栈头到栈底的顺序**,因为单纯的说从左到右或者从前到后,不说栈头朝哪个方向的话,大家一定会越看越懵。
这里我们要使用递增循序再强调一下是指从栈头到栈底的顺序因为只有递增的时候加入一个元素i才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i。
文字描述理解起来有点费劲,接下来我画了一系列的图,来讲解单调栈的工作过程。
使用单调栈主要有三个判断条件。
* 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
* 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
* 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
**把这三种情况分析清楚了,也就理解透彻了**
接下来我们用temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
首先先将第一个遍历元素加入单调栈
![739.每日温度1](https://img-blog.csdnimg.cn/20210219124434172.jpg)
加入T[1] = 74因为T[1] > T[0]当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况而我们要保持一个递增单调栈从栈头到栈底所以将T[0]弹出T[1]加入此时result数组可以记录了result[0] = 1即T[0]右面第一个比T[0]大的元素是T[1]。
![739.每日温度2](https://img-blog.csdnimg.cn/20210219124504299.jpg)
加入T[2]同理T[1]弹出
![739.每日温度3](https://img-blog.csdnimg.cn/20210219124527361.jpg)
加入T[3]T[3] < T[2] 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况加T[3]加入单调栈
![739.每日温度4](https://img-blog.csdnimg.cn/20210219124610761.jpg)
加入T[4]T[4] == T[3] 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况此时依然要加入栈不用计算距离因为我们要求的是右面第一个大于本元素的位置而不是大于等于
![739.每日温度5](https://img-blog.csdnimg.cn/20210219124633444.jpg)
加入T[5]T[5] > T[4] 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况将T[4]弹出同时计算距离更新result
![739.每日温度6](https://img-blog.csdnimg.cn/20210219124700567.jpg)
T[4]弹出之后, T[5] > T[3] 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况将T[3]继续弹出同时计算距离更新result
![739.每日温度7](https://img-blog.csdnimg.cn/20210219124726613.jpg)
直到发现T[5]小于T[st.top()]终止弹出将T[5]加入单调栈
![739.每日温度8](https://img-blog.csdnimg.cn/20210219124807715.jpg)
加入T[6]同理需要将栈里的T[5]T[2]弹出
![739.每日温度9](https://img-blog.csdnimg.cn/2021021912483374.jpg)
同理,继续弹出
![739.每日温度10](https://img-blog.csdnimg.cn/2021021912490098.jpg)
此时栈里只剩下了T[6]
![739.每日温度11](https://img-blog.csdnimg.cn/20210219124930156.jpg)
加入T[7] T[7] < T[6] 直接入栈这就是最后的情况result数组也更新完了
![739.每日温度12](https://img-blog.csdnimg.cn/20210219124957216.jpg)
此时有同学可能就疑惑了那result[6] , result[7]怎么没更新啊元素也一直在栈里
其实定义result数组的时候就应该直接初始化为0如果result没有更新说明这个元素右面没有更大的了也就是为0
以上在图解的时候已经把这三种情况都做了详细的分析
* 情况一当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
* 情况二当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
* 情况三当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
C++代码如下
```C++
// 版本一
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
// 递减栈
stack<int> st;
vector<int> result(T.size(), 0);
st.push(0);
for (int i = 1; i < T.size(); i++) {
if (T[i] < T[st.top()]) { // 情况一
st.push(i);
} else if (T[i] == T[st.top()]) { // 情况二
st.push(i);
} else {
while (!st.empty() && T[i] > T[st.top()]) { // 情况三
result[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
}
return result;
}
};
```
**建议一开始 都把每种情况分析好,不要上来看简短的代码,关键逻辑都被隐藏了**。
精简代码如下:
```C++
// 版本二
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
stack<int> st; // 递减栈
vector<int> result(T.size(), 0);
st.push(0);
for (int i = 1; i < T.size(); i++) {
while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
result[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
return result;
}
};
```
* 时间复杂度O(n)
* 空间复杂度O(n)
精简的代码是直接把情况一二三都合并到了一起,其实这种代码精简是精简,但思路不是很清晰。
建议大家把情况一二三想清楚了,先写出版本一的代码,然后在其基础上在做精简!
## 其他语言版本
Java
```java
/**
* 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到笑
* <p>
* 入站元素要和当前栈内栈首元素进行比较
* 若大于栈首则 则与元素下标做差
* 若大于等于则放入
*
* @param temperatures
* @return
*/
public static int[] dailyTemperatures(int[] temperatures) {
Stack<Integer> stack = new Stack<>();
int[] res = new int[temperatures.length];
for (int i = 0; i < temperatures.length; i++) {
/**
* 取出下标进行元素值的比较
*/
while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
int preIndex = stack.pop();
res[preIndex] = i - preIndex;
}
/**
* 注意 放入的是元素位置
*/
stack.push(i);
}
return res;
}
```
Python
Go
> 暴力法
```go
func dailyTemperatures(temperatures []int) []int {
length:=len(temperatures)
res:=make([]int,length)
for i:=0;i<length;i++{
j:=i+1
if i==length-1{
res[i]=0
}
for j<length&&temperatures[i]>=temperatures[j]{//大于等于
j++
}
if j<length&&temperatures[i]<temperatures[j]{
res[i]=j-i
}
if j==length{
res[i]=0
}
}
return res
}
```
> 单调栈法
```go
func dailyTemperatures(temperatures []int) []int {
length:=len(temperatures)
res:=make([]int,length)
stack:=[]int{}
for i:=0;i<length;i++{
//如果当前栈中存在元素,新来的元素大于栈顶的元素,则计算差值并弹出栈顶元素
for len(stack)>0&&temperatures[i]>temperatures[stack[len(stack)-1]]{
res[stack[len(stack)-1]]=i-stack[len(stack)-1]//存放结果集
stack=stack[:len(stack)-1]//删除stack[len(stack)-1]的元素
}
//如果栈顶元素大于等于新来的元素则加入到栈中。当栈内元素个数为0时直接入栈
if len(stack)==0||temperatures[i]<=temperatures[stack[len(stack)-1]]{
stack = append(stack, i)
}
}
return res
}
```
-----------------------
* 作者微信[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>

View File

@ -255,7 +255,18 @@ func min(a, b int) int {
}
```
Javascript
```Javascript
var minCostClimbingStairs = function(cost) {
const dp = [ cost[0], cost[1] ]
for (let i = 2; i < cost.length; ++i) {
dp[i] = Math.min(dp[i -1] + cost[i], dp[i - 2] + cost[i])
}
return Math.min(dp[cost.length - 1], dp[cost.length - 2])
};
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -128,7 +128,26 @@ class Solution:
Go
Javascript:
```Javascript
var partitionLabels = function(s) {
let hash = {}
for(let i = 0; i < s.length; i++) {
hash[s[i]] = i
}
let result = []
let left = 0
let right = 0
for(let i = 0; i < s.length; i++) {
right = Math.max(right, hash[s[i]])
if(right === i) {
result.push(right - left + 1)
left = i + 1
}
}
return result
};
```
-----------------------

View File

@ -184,7 +184,38 @@ class Solution:
Go
Javascript:
```Javascript
var lemonadeChange = function(bills) {
let fiveCount = 0
let tenCount = 0
for(let i = 0; i < bills.length; i++) {
let bill = bills[i]
if(bill === 5) {
fiveCount += 1
} else if (bill === 10) {
if(fiveCount > 0) {
fiveCount -=1
tenCount += 1
} else {
return false
}
} else {
if(tenCount > 0 && fiveCount > 0) {
tenCount -= 1
fiveCount -= 1
} else if(fiveCount >= 3) {
fiveCount -= 3
} else {
return false
}
}
}
return true
};
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -369,7 +369,42 @@ class Solution:
```
Go
Javascript:
```Javascript
var minCameraCover = function(root) {
let result = 0
function traversal(cur) {
if(cur === null) {
return 2
}
let left = traversal(cur.left)
let right = traversal(cur.right)
if(left === 2 && right === 2) {
return 0
}
if(left === 0 || right === 0) {
result++
return 1
}
if(left === 1 || right === 1) {
return 2
}
return -1
}
if(traversal(root) === 0) {
result++
}
return result
};
```
-----------------------

View File

@ -96,8 +96,46 @@ public:
## 其他语言版本
Java
```Java
class Solution {
public int[] sortedSquares(int[] nums) {
int right = nums.length - 1;
int left = 0;
int[] result = new int[nums.length];
int index = result.length - 1;
while (left <= right) {
if (nums[left] * nums[left] > nums[right] * nums[right]) {
result[index--] = nums[left] * nums[left];
++left;
} else {
result[index--] = nums[right] * nums[right];
--right;
}
}
return result;
}
}
```
```java
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0;
int r = nums.length - 1;
int[] res = new int[nums.length];
int j = nums.length - 1;
while(l <= r){
if(nums[l] * nums[l] > nums[r] * nums[r]){
res[j--] = nums[l] * nums[l++];
}else{
res[j--] = nums[r] * nums[r--];
}
}
return res;
}
}
```
Python
```Python
@ -160,6 +198,31 @@ impl Solution {
}
}
```
Javascript
```Javascript
/**
* @desc two pointers solution
* @link https://leetcode-cn.com/problems/squares-of-a-sorted-array/
* @param nums Array e.g. [-4,-1,0,3,10]
* @return {array} e.g. [0,1,9,16,100]
*/
const sortedSquares = function (nums) {
let res = []
for (let i = 0, j = nums.length - 1; i <= j;) {
const left = Math.abs(nums[i])
const right = Math.abs(nums[j])
if (right > left) {
// push element to the front of the array
res.unshift(right * right)
j--
} else {
res.unshift(left * left)
i++
}
}
return res
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -133,11 +133,35 @@ class Solution:
A[i] *= -1
K -= 1
if K > 0:
A[len(A) - 1] *= ((-1)**K)
A[-1] *= (-1)**K #取A最后一个数只需要写-1
return sum(A)
```
Go
```Go
func largestSumAfterKNegations(nums []int, K int) int {
sort.Slice(nums, func(i, j int) bool {
return math.Abs(float64(nums[i])) > math.Abs(float64(nums[j]))
})
for i := 0; i < len(nums); i++ {
if K > 0 && nums[i] < 0 {
nums[i] = -nums[i]
K--
}
}
if K%2 == 1 {
nums[len(nums)-1] = -nums[len(nums)-1]
}
result := 0
for i := 0; i < len(nums); i++ {
result += nums[i]
}
return result
}
```
Javascript:

View File

@ -93,7 +93,18 @@ Java
```
Python
```python
class Solution:
def maxUncrossedLines(self, A: List[int], B: List[int]) -> int:
dp = [[0] * (len(B)+1) for _ in range(len(A)+1)]
for i in range(1, len(A)+1):
for j in range(1, len(B)+1):
if A[i-1] == B[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 dp[-1][-1]
```
Go

View File

@ -257,9 +257,190 @@ Java
Python
100.相同的树
> 递归法
```python
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
return self.compare(p, q)
def compare(self, tree1, tree2):
if not tree1 and tree2:
return False
elif tree1 and not tree2:
return False
elif not tree1 and not tree2:
return True
elif tree1.val != tree2.val: #注意这里我没有使用else
return False
#此时就是:左右节点都不为空,且数值相同的情况
#此时才做递归,做下一层的判断
compareLeft = self.compare(tree1.left, tree2.left) #左子树:左、 右子树:左
compareRight = self.compare(tree1.right, tree2.right) #左子树:右、 右子树:右
isSame = compareLeft and compareRight #左子树:中、 右子树:中(逻辑处理)
return isSame
```
257.二叉的所有路径
> 递归中隐藏着回溯
```python
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
result = []
path = []
if not root:
return result
self.traversal(root, path, result)
return result
def traversal(self, cur, path, result):
path.append(cur.val)
#这才到了叶子节点
if not cur.left and not cur.right:
sPath = ""
for i in range(len(path)-1):
sPath += str(path[i])
sPath += "->"
sPath += str(path[len(path)-1])
result.append(sPath)
return
if cur.left:
self.traversal(cur.left, path, result)
path.pop() #回溯
if cur.right:
self.traversal(cur.right, path, result)
path.pop() #回溯
```
> 精简版
```python
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
result = []
path = ""
if not root:
return result
self.traversal(root, path, result)
return result
def traversal(self, cur, path, result):
path += str(cur.val) #中
if not cur.left and not cur.right:
result.append(path)
return
if cur.left:
self.traversal(cur.left, path+"->", result) #左 回溯就隐藏在这里
if cur.right:
self.traversal(cur.right, path+"->", result) #右 回溯就隐藏在这里
```
Go
100.相同的树
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func isSameTree(p *TreeNode, q *TreeNode) bool {
switch {
case p == nil && q == nil:
return true
case p == nil || q == nil:
fallthrough
case p.Val != q.Val:
return false
}
return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}
```
257.二叉的所有路径
> 递归法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func binaryTreePaths(root *TreeNode) []string {
var result []string
traversal(root,&result,"")
return result
}
func traversal(root *TreeNode,result *[]string,pathStr string){
//判断是否为第一个元素
if len(pathStr)!=0{
pathStr=pathStr+"->"+strconv.Itoa(root.Val)
}else{
pathStr=strconv.Itoa(root.Val)
}
//判断是否为叶子节点
if root.Left==nil&&root.Right==nil{
*result=append(*result,pathStr)
return
}
//左右
if root.Left!=nil{
traversal(root.Left,result,pathStr)
}
if root.Right!=nil{
traversal(root.Right,result,pathStr)
}
}
```
> 回溯法
```go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func binaryTreePaths(root *TreeNode) []string {
var result []string
var path []int
traversal(root,&result,&path)
return result
}
func traversal(root *TreeNode,result *[]string,path *[]int){
*path=append(*path,root.Val)
//判断是否为叶子节点
if root.Left==nil&&root.Right==nil{
pathStr:=strconv.Itoa((*path)[0])
for i:=1;i<len(*path);i++{
pathStr=pathStr+"->"+strconv.Itoa((*path)[i])
}
*result=append(*result,pathStr)
return
}
//左右
if root.Left!=nil{
traversal(root.Left,result,path)
*path=(*path)[:len(*path)-1]//回溯到上一个节点因为traversal会加下一个节点值到path中
}
if root.Right!=nil{
traversal(root.Right,result,path)
*path=(*path)[:len(*path)-1]//回溯
}
}
```

View File

@ -221,7 +221,7 @@ class Solution:
Go
前序遍历:
```
```go
func PreorderTraversal(root *TreeNode) (res []int) {
var traversal func(node *TreeNode)
traversal = func(node *TreeNode) {
@ -239,7 +239,7 @@ func PreorderTraversal(root *TreeNode) (res []int) {
```
中序遍历:
```
```go
func InorderTraversal(root *TreeNode) (res []int) {
var traversal func(node *TreeNode)
traversal = func(node *TreeNode) {
@ -256,7 +256,7 @@ func InorderTraversal(root *TreeNode) (res []int) {
```
后序遍历:
```
```go
func PostorderTraversal(root *TreeNode) (res []int) {
var traversal func(node *TreeNode)
traversal = func(node *TreeNode) {

View File

@ -42,9 +42,9 @@ i指向新长度的末尾j指向旧长度的末尾。
时间复杂度空间复杂度均超过100%的用户。
<img src='https://code-thinking.cdn.bcebos.com/pics/%E5%89%91%E6%8C%87Offer05.%E6%9B%BF%E6%8D%A2%E7%A9%BA%E6%A0%BC.png' width=600> </img></div>
<img src='https://code-thinking.cdn.bcebos.com/pics/剑指Offer05.替换空格.png' width=600> </img></div>
## C++代码
C++代码如下:
```C++
class Solution {
@ -76,17 +76,17 @@ public:
};
```
时间复杂度O(n)
空间复杂度O(1)
* 时间复杂度O(n)
* 空间复杂度O(1)
此时算上本题,我们已经做了七道双指针相关的题目了分别是:
* [27.移除元素](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA)
* [15.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A)
* [18.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)
* [206.翻转链表](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)
* [142.环形链表II](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)
* [344.反转字符串](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA)
* [27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)
* [15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)
* [18.四数之和](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q)
* [206.翻转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)
* [142.环形链表II](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)
* [344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)
# 拓展
@ -121,10 +121,6 @@ for (int i = 0; i < a.size(); i++) {
所以想处理字符串我们还是会定义一个string类型。
## 其他语言版本
@ -150,11 +146,56 @@ public static String replaceSpace(StringBuffer str) {
}
```
Python
Go
```go
// 遍历添加
func replaceSpace(s string) string {
b := []byte(s)
result := make([]byte, 0)
for i := 0; i < len(b); i++ {
if b[i] == ' ' {
result = append(result, []byte("%20")...)
} else {
result = append(result, b[i])
}
}
return string(result)
}
// 原地修改
func replaceSpace(s string) string {
b := []byte(s)
length := len(b)
spaceCount := 0
// 计算空格数量
for _, v := range b {
if v == ' ' {
spaceCount++
}
}
// 扩展原有切片
resizeCount := spaceCount * 2
tmp := make([]byte, resizeCount)
b = append(b, tmp...)
i := length - 1
j := len(b) - 1
for i >= 0 {
if b[i] != ' ' {
b[j] = b[i]
i--
j--
} else {
b[j] = '0'
b[j-1] = '2'
b[j-2] = '%'
i--
j = j - 3
}
}
return string(b)
}
```

View File

@ -34,7 +34,7 @@ https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
不能使用额外空间的话模拟在本串操作要实现左旋转字符串的功能还是有点困难的
那么我们可以想一下上一题目[字符串:花式反转还不够!](https://mp.weixin.qq.com/s/X3qpi2v5RSp08mO-W5Vicw)中讲过使用整体反转+局部反转就可以实现反转单词顺序的目的
那么我们可以想一下上一题目[字符串:花式反转还不够!](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)中讲过使用整体反转+局部反转就可以实现反转单词顺序的目的
这道题目也非常类似依然可以通过局部反转+整体反转 达到左旋转的目的
@ -50,13 +50,13 @@ https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
如图
<img src='https://code-thinking.cdn.bcebos.com/pics/%E5%89%91%E6%8C%87Offer58-II.%E5%B7%A6%E6%97%8B%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2.png' width=600> </img></div>
<img src='https://code-thinking.cdn.bcebos.com/pics/剑指Offer58-II.左旋转字符串.png' width=600> </img></div>
最终得到左旋2个单元的字符串cdefgab
思路明确之后,那么代码实现就很简单了
# C++代码
C++代码如下:
```C++
class Solution {
@ -73,15 +73,16 @@ public:
# 总结
此时我们已经反转好多次字符串了,来一起回顾一下吧。
在这篇文章[字符串:这道题目,使用库函数一行代码搞定](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA),第一次讲到反转一个字符串应该怎么做,使用了双指针法。
在这篇文章[344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w),第一次讲到反转一个字符串应该怎么做,使用了双指针法。
然后发现[字符串:简单的反转还不够!](https://mp.weixin.qq.com/s/XGSk1GyPWhfqj2g7Cb1Vgw)这里开始给反转加上了一些条件当需要固定规律一段一段去处理字符串的时候要想想在在for循环的表达式上做做文章。
然后发现[541. 反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ)这里开始给反转加上了一些条件当需要固定规律一段一段去处理字符串的时候要想想在在for循环的表达式上做做文章。
后来在[字符串:花式反转还不够!](https://mp.weixin.qq.com/s/X3qpi2v5RSp08mO-W5Vicw)中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。
后来在[151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。
最后再讲到本,本题则是先局部反转再 整体反转,与[字符串:花式反转还不够!](https://mp.weixin.qq.com/s/X3qpi2v5RSp08mO-W5Vicw)类似,但是也是一种新的思路。
最后再讲到本,本题则是先局部反转再 整体反转,与[151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)类似,但是也是一种新的思路。
好了,反转字符串一共就介绍到这里,相信大家此时对反转字符串的常见操作已经很了解了。
@ -93,7 +94,6 @@ public:
**如果想让这套题目有意义,就不要申请额外空间。**
## 其他语言版本
Java
@ -117,7 +117,6 @@ class Solution {
}
}
```
Python
Go

View File

@ -9,11 +9,10 @@
> 哈希表总结篇如约而至
哈希表系列也是早期讲解的时候没有写总结篇,所以选个周末给补上,毕竟「代码随想录」的系列怎么能没有总结篇呢[机智]。
# 哈希表理论基础
在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)中,我们介绍了哈希表的基础理论知识,不同于枯燥的讲解,这里介绍了都是对刷题有帮助的理论知识点。
在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中,我们介绍了哈希表的基础理论知识,不同于枯燥的讲解,这里介绍了都是对刷题有帮助的理论知识点。
**一般来说哈希表都是用来快速判断一个元素是否出现集合里**
@ -29,7 +28,7 @@
* set集合
* map映射
在C++语言中set 和 map 都分别提供了三种数据结构,每种数据结构的底层实现和用途都有所不同,在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)中我给出了详细分析,这一知识点很重要!
在C++语言中set 和 map 都分别提供了三种数据结构,每种数据结构的底层实现和用途都有所不同,在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中我给出了详细分析,这一知识点很重要!
例如什么时候用std::set什么时候用std::multiset什么时候用std::unordered_set都是很有考究的。
@ -41,13 +40,13 @@
一些应用场景就是为数组量身定做的。
在[哈希表:有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)中,我们提到了数组就是简单的哈希表,但是数组的大小是受限的!
在[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)中,我们提到了数组就是简单的哈希表,但是数组的大小是受限的!
这道题目包含小写字母,那么使用数组来做哈希最合适不过。
在[哈希表:赎金信](https://mp.weixin.qq.com/s/sYZIR4dFBrw_lr3eJJnteQ)中同样要求只有小写字母,那么就给我们浓浓的暗示,用数组!
在[383.赎金信](https://mp.weixin.qq.com/s/qAXqv--UERmiJNNpuphOUQ)中同样要求只有小写字母,那么就给我们浓浓的暗示,用数组!
本题和[哈希表:有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)很像,[哈希表:有效的字母异位词](https://mp.weixin.qq.com/s/vM6OszkM6L1Mx2Ralm9Dig)是求 字符串a 和 字符串b 是否可以相互组成,在[哈希表:赎金信](https://mp.weixin.qq.com/s/sYZIR4dFBrw_lr3eJJnteQ)中是求字符串a能否组成字符串b而不用管字符串b 能不能组成字符串a。
本题和[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)是求 字符串a 和 字符串b 是否可以相互组成,在[383.赎金信](https://mp.weixin.qq.com/s/qAXqv--UERmiJNNpuphOUQ)中是求字符串a能否组成字符串b而不用管字符串b 能不能组成字符串a。
一些同学可能想用数组干啥都用map不就完事了。
@ -56,7 +55,7 @@
## set作为哈希表
在[哈希表:两个数组的交集](https://mp.weixin.qq.com/s/N9iqAchXreSVW7zXUS4BVA)中我们给出了什么时候用数组就不行了需要用set。
在[349. 两个数组的交集](https://mp.weixin.qq.com/s/aMSA5zrp3jJcLjuSB0Es2Q)中我们给出了什么时候用数组就不行了需要用set。
这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
@ -67,7 +66,7 @@
所以此时一样的做映射的话就可以使用set了。
关于setC++ 给提供了如下三种可用的数据结构:(详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)
关于setC++ 给提供了如下三种可用的数据结构:(详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)
* std::set
* std::multiset
@ -75,12 +74,12 @@
std::set和std::multiset底层实现都是红黑树std::unordered_set的底层实现是哈希 使用unordered_set 读写效率是最高的本题并不需要对数据进行排序而且还不要让数据重复所以选择unordered_set。
在[哈希表:快乐数](https://mp.weixin.qq.com/s/G4Q2Zfpfe706gLK7HpZHpA)中我们再次使用了unordered_set来判断一个数是否重复出现过。
在[202.快乐数](https://mp.weixin.qq.com/s/n5q0ujxxrjQS3xuh3dgqBQ)中我们再次使用了unordered_set来判断一个数是否重复出现过。
## map作为哈希表
在[哈希表:两数之和](https://mp.weixin.qq.com/s/uVAtjOHSeqymV8FeQbliJQ)中map正式登场。
在[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)中map正式登场。
来说一说使用数组和set来做哈希法的局限。
@ -89,7 +88,7 @@ std::set和std::multiset底层实现都是红黑树std::unordered_set的底
map是一种`<key, value>`的结构本题可以用key保存数值用value在保存数值所在的下表。所以使用map最为合适。
C++提供如下三种map详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)
C++提供如下三种map详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)
* std::map
* std::multimap
@ -97,21 +96,21 @@ C++提供如下三种map详情请看[关于哈希表,你该了解这
std::unordered_map 底层实现为哈希std::map 和std::multimap 的底层实现是红黑树。
同理std::map 和std::multimap 的key也是有序的这个问题也经常作为面试题考察对语言容器底层的理解[哈希表:两数之和](https://mp.weixin.qq.com/s/uVAtjOHSeqymV8FeQbliJQ)中并不需要key有序选择std::unordered_map 效率更高!
同理std::map 和std::multimap 的key也是有序的这个问题也经常作为面试题考察对语言容器底层的理解[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)中并不需要key有序选择std::unordered_map 效率更高!
在[哈希表:四数相加II](https://mp.weixin.qq.com/s/Ue8pKKU5hw_m-jPgwlHcbA)中我们提到了其实需要哈希的地方都能找到map的身影。
在[454.四数相加](https://mp.weixin.qq.com/s/12g_w6RzHuEpFts1pT6BWw)中我们提到了其实需要哈希的地方都能找到map的身影。
本题咋眼一看好像和[18. 四数之](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A)[15.三数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)差不多,其实差很多!
本题咋眼一看好像和[18. 四数之](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q)[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)差不多,其实差很多!
**关键差别是本题为四个独立的数组只要找到A[i] + B[j] + C[k] + D[l] = 0就可以不用考虑重复问题而[18. 四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)[15.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A)是一个数组集合里找到和为0的组合可就难很多了**
**关键差别是本题为四个独立的数组只要找到A[i] + B[j] + C[k] + D[l] = 0就可以不用考虑重复问题而[18. 四数之和](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q)[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)是一个数组集合里找到和为0的组合可就难很多了**
用哈希法解决了两数之和,很多同学会感觉用哈希法也可以解决三数之和,四数之和。
其实是可以解决,但是非常麻烦,需要去重导致代码效率很低。
在[哈希表:解决了两数之和,那么能解决三数之和么?](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A)中我给出了哈希法和双指针两个解法,大家就可以体会到,使用哈希法还是比较麻烦的。
在[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)中我给出了哈希法和双指针两个解法,大家就可以体会到,使用哈希法还是比较麻烦的。
所以[18. 四数之](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A)[15.三数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)都推荐使用双指针法!
所以18. 四数之15.三数之和都推荐使用双指针法!
# 总结
@ -127,19 +126,6 @@ std::unordered_map 底层实现为哈希std::map 和std::multimap 的底层
## 其他语言版本
Java
Python
Go
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -85,20 +85,7 @@ std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
所以STL 队列也不被归类为容器而被归类为container adapter 容器适配器)。
我这里讲的都是clckC++ 语言中情况, 使用其他语言的同学也要思考栈与队列的底层实现问题, 不要对数据结构的使用浅尝辄止,而要深挖起内部原理,才能夯实基础。
## 其他语言版本
Java
Python
Go
我这里讲的都是C++ 语言中情况, 使用其他语言的同学也要思考栈与队列的底层实现问题, 不要对数据结构的使用浅尝辄止,而要深挖起内部原理,才能夯实基础。

View File

@ -265,15 +265,120 @@ int main() {
## 其他语言版本
Java
```java
public static void main(String[] args) {
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int bagSize = 4;
testWeightBagProblem(weight, value, bagSize);
}
public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){
int wLen = weight.length, value0 = 0;
//定义dp数组dp[i][j]表示背包容量为j时前i个物品能获得的最大价值
int[][] dp = new int[wLen + 1][bagSize + 1];
//初始化背包容量为0时能获得的价值都为0
for (int i = 0; i <= wLen; i++){
dp[i][0] = value0;
}
//遍历顺序:先遍历物品,再遍历背包容量
for (int i = 1; i <= wLen; i++){
for (int j = 1; j <= bagSize; j++){
if (j < weight[i - 1]){
dp[i][j] = dp[i - 1][j];
}else{
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);
}
}
}
//打印dp数组
for (int i = 0; i <= wLen; i++){
for (int j = 0; j <= bagSize; j++){
System.out.print(dp[i][j] + " ");
}
System.out.print("\n");
}
}
```
Python
```python
def test_2_wei_bag_problem1(bag_size, weight, value) -> int:
rows, cols = len(weight), bag_size + 1
dp = [[0 for _ in range(cols)] for _ in range(rows)]
res = 0
# 初始化dp数组.
for i in range(rows):
dp[i][0] = 0
first_item_weight, first_item_value = weight[0], value[0]
for j in range(1, cols):
if first_item_weight <= j:
dp[0][j] = first_item_value
# 更新dp数组: 先遍历物品, 再遍历背包.
for i in range(1, len(weight)):
cur_weight, cur_val = weight[i], value[i]
for j in range(1, cols):
if cur_weight > j: # 说明背包装不下当前物品.
dp[i][j] = dp[i - 1][j] # 所以不装当前物品.
else:
# 定义dp数组: dp[i][j] 前i个物品里放进容量为j的背包价值总和最大是多少。
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cur_weight]+ cur_val)
if dp[i][j] > res:
res = dp[i][j]
print(dp)
if __name__ == "__main__":
bag_size = 4
weight = [1, 3, 4]
value = [15, 20, 30]
test_2_wei_bag_problem1(bag_size, weight, value)
```
Go
```go
func test_2_wei_bag_problem1(weight, value []int, bagWeight int) int {
// 定义dp数组
dp := make([][]int, len(weight))
for i, _ := range dp {
dp[i] = make([]int, bagWeight+1)
}
// 初始化
for j := bagWeight; j >= weight[0]; j-- {
dp[0][j] = dp[0][j-weight[0]] + value[0]
}
// 递推公式
for i := 1; i < len(weight); i++ {
//正序,也可以倒序
for j := weight[i];j<= bagWeight ; j++ {
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i])
}
}
return dp[len(weight)-1][bagWeight]
}
func max(a,b int) int {
if a > b {
return a
}
return b
}
func main() {
weight := []int{1,3,4}
value := []int{15,20,30}
test_2_wei_bag_problem1(weight,value,4)
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -5,6 +5,7 @@
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
</p>
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 动态规划关于01背包问题你该了解这些滚动数组
昨天[动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中是用二维dp数组来讲解01背包。
@ -35,7 +36,7 @@
**其实可以发现如果把dp[i - 1]那一层拷贝到dp[i]上表达式完全可以是dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);**
**其把dp[i - 1]这一层拷贝到dp[i]上,不如只用一个一维数组了**只用dp[j](一维数组,也可以理解是一个滚动数组)。
**其把dp[i - 1]这一层拷贝到dp[i]上,不如只用一个一维数组了**只用dp[j](一维数组,也可以理解是一个滚动数组)。
这就是滚动数组的由来,需要满足的条件是上一层可以重复利用,直接拷贝到当前层。
@ -211,15 +212,87 @@ int main() {
## 其他语言版本
Java
```java
public static void main(String[] args) {
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int bagWight = 4;
testWeightBagProblem(weight, value, bagWight);
}
public static void testWeightBagProblem(int[] weight, int[] value, int bagWeight){
int wLen = weight.length;
//定义dp数组dp[j]表示背包容量为j时能获得的最大价值
int[] dp = new int[bagWeight + 1];
//遍历顺序:先遍历物品,再遍历背包容量
for (int i = 0; i < wLen; i++){
for (int j = bagWeight; j >= weight[i]; j--){
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
}
}
//打印dp数组
for (int j = 0; j <= bagWeight; j++){
System.out.print(dp[j] + " ");
}
}
```
Python
```python
def test_1_wei_bag_problem():
weight = [1, 3, 4]
value = [15, 20, 30]
bag_weight = 4
# 初始化: 全为0
dp = [0] * (bag_weight + 1)
# 先遍历物品, 再遍历背包容量
for i in range(len(weight)):
for j in range(bag_weight, weight[i] - 1, -1):
# 递归公式
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(dp)
test_1_wei_bag_problem()
```
Go
```go
func test_1_wei_bag_problem(weight, value []int, bagWeight int) int {
// 定义 and 初始化
dp := make([]int,bagWeight+1)
// 递推顺序
for i := 0 ;i < len(weight) ; i++ {
// 这里必须倒序,区别二维,因为二维dp保存了i的状态
for j:= bagWeight; j >= weight[i] ; j-- {
// 递推公式
dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
}
}
//fmt.Println(dp)
return dp[bagWeight]
}
func max(a,b int) int {
if a > b {
return a
}
return b
}
func main() {
weight := []int{1,3,4}
value := []int{15,20,30}
test_1_wei_bag_problem(weight,value,4)
}
```

View File

@ -147,9 +147,56 @@ int main() {
Java
Python
```python
def test_multi_pack1():
'''版本一改变物品数量为01背包格式'''
weight = [1, 3, 4]
value = [15, 20, 30]
nums = [2, 3, 2]
bag_weight = 10
for i in range(len(nums)):
# 将物品展开数量为1
while nums[i] > 1:
weight.append(weight[i])
value.append(value[i])
nums[i] -= 1
dp = [0]*(bag_weight + 1)
# 遍历物品
for i in range(len(weight)):
# 遍历背包
for j in range(bag_weight, weight[i] - 1, -1):
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(" ".join(map(str, dp)))
def test_multi_pack2():
'''版本:改变遍历个数'''
weight = [1, 3, 4]
value = [15, 20, 30]
nums = [2, 3, 2]
bag_weight = 10
dp = [0]*(bag_weight + 1)
for i in range(len(weight)):
for j in range(bag_weight, weight[i] - 1, -1):
# 以上是01背包加上遍历个数
for k in range(1, nums[i] + 1):
if j - k*weight[i] >= 0:
dp[j] = max(dp[j], dp[j - k*weight[i]] + k*value[i])
print(" ".join(map(str, dp)))
if __name__ == '__main__':
test_multi_pack1()
test_multi_pack2()
```
Go

View File

@ -220,7 +220,58 @@ if __name__ == '__main__':
Go
```go
// test_CompletePack1 先遍历物品, 在遍历背包
func test_CompletePack1(weight, value []int, bagWeight int) int {
// 定义dp数组 和初始化
dp := make([]int, bagWeight+1)
// 遍历顺序
for i := 0; i < len(weight); i++ {
// 正序会多次添加 value[i]
for j := weight[i]; j <= bagWeight; j++ {
// 推导公式
dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
// debug
//fmt.Println(dp)
}
}
return dp[bagWeight]
}
// test_CompletePack2 先遍历背包, 在遍历物品
func test_CompletePack2(weight, value []int, bagWeight int) int {
// 定义dp数组 和初始化
dp := make([]int, bagWeight+1)
// 遍历顺序
// j从0 开始
for j := 0; j <= bagWeight; j++ {
for i := 0; i < len(weight); i++ {
if j >= weight[i] {
// 推导公式
dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
}
// debug
//fmt.Println(dp)
}
}
return dp[bagWeight]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func main() {
weight := []int{1, 3, 4}
price := []int{15, 20, 30}
fmt.Println(test_CompletePack1(weight, price, 4))
fmt.Println(test_CompletePack2(weight, price, 4))
}
```

View File

@ -32,11 +32,11 @@
看如下两个链表目前curA指向链表A的头结点curB指向链表B的头结点
![面试题02.07.链表相交_1](https://code-thinking.cdn.bcebos.com/pics/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4_1.png)v
![面试题02.07.链表相交_1](https://code-thinking.cdn.bcebos.com/pics/面试题02.07.链表相交_1.png)
我们求出两个链表的长度并求出两个链表长度的差值然后让curA移动到和curB 末尾对齐的位置,如图:
![面试题02.07.链表相交_2](https://code-thinking.cdn.bcebos.com/pics/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4_2.png)
![面试题02.07.链表相交_2](https://code-thinking.cdn.bcebos.com/pics/面试题02.07.链表相交_2.png)
此时我们就可以比较curA和curB是否相同如果不相同同时向后移动curA和curB如果遇到curA == curB则找到焦点。