mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-09 02:53:31 +08:00
Merge branch 'master' of github.com:flames519/leetcode-master
This commit is contained in:
14
README.md
14
README.md
@ -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://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>
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
</p>
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ" target="_blank">
|
||||||
|
<img src="./pics/知识星球.png" width="600"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
# LeetCode 刷题攻略
|
# LeetCode 刷题攻略
|
||||||
|
|
||||||
@ -120,6 +125,10 @@
|
|||||||
4. [马上秋招了,慌得很!](https://mp.weixin.qq.com/s/7q7W8Cb2-a5U5atZdOnOFA)
|
4. [马上秋招了,慌得很!](https://mp.weixin.qq.com/s/7q7W8Cb2-a5U5atZdOnOFA)
|
||||||
5. [Carl看了上百份简历,总结了这些!](https://mp.weixin.qq.com/s/sJa87MZD28piCOVMFkIbwQ)
|
5. [Carl看了上百份简历,总结了这些!](https://mp.weixin.qq.com/s/sJa87MZD28piCOVMFkIbwQ)
|
||||||
6. [面试中遇到了发散性问题.....](https://mp.weixin.qq.com/s/SSonDxi2pjkSVwHNzZswng)
|
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)
|
54. [动态规划:最长回文子序列](./problems/0516.最长回文子序列.md)
|
||||||
55. [动态规划总结篇](./problems/动态规划总结篇.md)
|
55. [动态规划总结篇](./problems/动态规划总结篇.md)
|
||||||
|
|
||||||
|
|
||||||
(持续更新中....)
|
(持续更新中....)
|
||||||
|
|
||||||
|
## 单调栈
|
||||||
|
|
||||||
|
1. [每日温度](./problems/0739.每日温度.md)
|
||||||
|
|
||||||
## 图论
|
## 图论
|
||||||
|
|
||||||
## 十大排序
|
## 十大排序
|
||||||
|
@ -107,7 +107,7 @@ public int[] twoSum(int[] nums, int target) {
|
|||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def twoSum(self, nums: List[int], target: int) -> List[int]:
|
def twoSum(self, nums: List[int], target: int) -> List[int]:
|
||||||
hashmap={}
|
hashmap={}
|
||||||
|
@ -321,6 +321,59 @@ class Solution:
|
|||||||
backtrack(board)
|
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:
|
Go:
|
||||||
|
|
||||||
Javascript:
|
Javascript:
|
||||||
|
@ -353,14 +353,6 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 其他语言版本
|
|
||||||
|
|
||||||
|
|
||||||
Java:
|
|
||||||
|
|
||||||
|
|
||||||
Python:
|
|
||||||
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
```Go
|
```Go
|
||||||
|
@ -95,10 +95,47 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
||||||
|
```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:
|
Go:
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -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]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -148,9 +148,44 @@ class Solution {
|
|||||||
Python:
|
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]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -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]**。
|
**dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]**。
|
||||||
|
|
||||||
@ -59,49 +61,65 @@ exection -> execution (插入 'u')
|
|||||||
|
|
||||||
用i来表示也可以! 但我统一以下标i-1为结尾的字符串,在下面的递归公式中会容易理解一点。
|
用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的最近编辑距离 加上一个增加元素的操作。
|
操作二: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]**。
|
**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;
|
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]`
|
||||||
* dp[i][j] = dp[i - 1][j - 1] + 1
|
* `dp[i][j] = dp[i - 1][j - 1] + 1`
|
||||||
* dp[i][j] = dp[i][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][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矩阵状态图如下:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -195,7 +220,7 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
-----------------------
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
@ -228,7 +253,22 @@ public int minDistance(String word1, String word2) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -338,6 +338,46 @@ class Solution(object):
|
|||||||
return ans```
|
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:
|
JavaScript:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -98,15 +98,13 @@ class Solution:
|
|||||||
out_list = []
|
out_list = []
|
||||||
|
|
||||||
while quene:
|
while quene:
|
||||||
|
length = len(queue)
|
||||||
in_list = []
|
in_list = []
|
||||||
for _ in range(len(quene)):
|
for _ in range(length):
|
||||||
node = quene.pop(0)
|
curnode = queue.pop(0) # (默认移除列表最后一个元素)这里需要移除队列最头上的那个
|
||||||
in_list.append(node.val)
|
in_list.append(curnode.val)
|
||||||
if node.left:
|
if curnode.left: queue.append(curnode.left)
|
||||||
quene.append(node.left)
|
if curnode.right: queue.append(curnode.right)
|
||||||
if node.right:
|
|
||||||
quene.append(node.right)
|
|
||||||
|
|
||||||
out_list.append(in_list)
|
out_list.append(in_list)
|
||||||
|
|
||||||
return out_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代码:
|
||||||
|
|
||||||
```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
|
## 117.填充每个节点的下一个右侧节点指针II
|
||||||
|
|
||||||
题目地址:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-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
|
||||||
|
```
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
|
@ -693,6 +693,70 @@ class Solution:
|
|||||||
return root
|
return root
|
||||||
```
|
```
|
||||||
Go:
|
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
|
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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
@ -486,6 +486,92 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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:
|
JavaScript:
|
||||||
|
|
||||||
0112.路径总和
|
0112.路径总和
|
||||||
|
@ -145,10 +145,46 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
||||||
|
```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:
|
Go:
|
||||||
|
|
||||||
|
@ -244,6 +244,47 @@ class Solution { // 动态规划解法
|
|||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -171,6 +171,33 @@ class Solution
|
|||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -229,6 +229,40 @@ class Solution { // 动态规划
|
|||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -240,6 +240,25 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
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:
|
||||||
```Javascript
|
```Javascript
|
||||||
|
@ -252,6 +252,23 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -50,12 +50,15 @@ https://leetcode-cn.com/problems/reverse-words-in-a-string/
|
|||||||
* 将整个字符串反转
|
* 将整个字符串反转
|
||||||
* 将每个单词反转
|
* 将每个单词反转
|
||||||
|
|
||||||
如动画所示:
|
举个例子,源字符串为:"the sky is blue "
|
||||||
|
|
||||||

|
* 移除多余空格 : "the sky is blue"
|
||||||
|
* 字符串反转:"eulb si yks eht"
|
||||||
|
* 单词反转:"blue is sky the"
|
||||||
|
|
||||||
这样我们就完成了翻转字符串里的单词。
|
这样我们就完成了翻转字符串里的单词。
|
||||||
|
|
||||||
|
|
||||||
思路很明确了,我们说一说代码的实现细节,就拿移除多余空格来说,一些同学会上来写如下代码:
|
思路很明确了,我们说一说代码的实现细节,就拿移除多余空格来说,一些同学会上来写如下代码:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
@ -80,13 +83,13 @@ void removeExtraSpaces(string& s) {
|
|||||||
|
|
||||||
如果不仔细琢磨一下erase的时间复杂读,还以为以上的代码是O(n)的时间复杂度呢。
|
如果不仔细琢磨一下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)。
|
erase操作上面还套了一个for循环,那么以上代码移除冗余空格的代码时间复杂度为O(n^2)。
|
||||||
|
|
||||||
那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。
|
那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。
|
||||||
|
|
||||||
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA)是如何移除元素的。
|
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)是如何移除元素的。
|
||||||
|
|
||||||
那么使用双指针来移除冗余空格代码如下: fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。
|
那么使用双指针来移除冗余空格代码如下: fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。
|
||||||
|
|
||||||
@ -122,7 +125,7 @@ void removeExtraSpaces(string& s) {
|
|||||||
|
|
||||||
此时我们已经实现了removeExtraSpaces函数来移除冗余空格。
|
此时我们已经实现了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++
|
```C++
|
||||||
// 版本一
|
// 版本一
|
||||||
@ -183,7 +183,7 @@ public:
|
|||||||
int end = 0; // 反转的单词在字符串里终止位置
|
int end = 0; // 反转的单词在字符串里终止位置
|
||||||
bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
|
bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
|
||||||
for (int i = 0; i < s.size(); i++) { // 开始反转单词
|
for (int i = 0; i < s.size(); i++) { // 开始反转单词
|
||||||
if ((!entry))) {
|
if (!entry) {
|
||||||
start = i; // 确定单词起始位置
|
start = i; // 确定单词起始位置
|
||||||
entry = true; // 进入单词区间
|
entry = true; // 进入单词区间
|
||||||
}
|
}
|
||||||
@ -203,6 +203,7 @@ public:
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 当然这里的主函数reverseWords写的有一些冗余的,可以精简一些,精简之后的主函数为:
|
||||||
/* 主函数简单写法
|
/* 主函数简单写法
|
||||||
string reverseWords(string s) {
|
string reverseWords(string s) {
|
||||||
removeExtraSpaces(s);
|
removeExtraSpaces(s);
|
||||||
@ -220,25 +221,8 @@ public:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
当然这里的主函数reverseWords写的有一些冗余的,可以精简一些,精简之后的主函数为:
|
效率:
|
||||||
|
<img src='https://code-thinking.cdn.bcebos.com/pics/151_翻转字符串里的单词.png' width=600> </img></div>
|
||||||
```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;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -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:
|
Go:
|
||||||
|
|
||||||
|
2
problems/0160.相交链表.md
Normal file
2
problems/0160.相交链表.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
同:[链表:链表相交](./面试题02.07.链表相交.md)
|
@ -212,6 +212,20 @@ class Solution { //动态规划
|
|||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class Solution {
|
|||||||
if (nums == null || nums.length == 0) return 0;
|
if (nums == null || nums.length == 0) return 0;
|
||||||
if (nums.length == 1) return nums[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[0] = nums[0];
|
||||||
dp[1] = Math.max(dp[0], nums[1]);
|
dp[1] = Math.max(dp[0], nums[1]);
|
||||||
for (int i = 2; i < nums.length; i++) {
|
for (int i = 2; i < nums.length; i++) {
|
||||||
@ -131,7 +131,20 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -118,8 +118,8 @@ public:
|
|||||||
|
|
||||||
## 相关题目推荐
|
## 相关题目推荐
|
||||||
|
|
||||||
* 904.水果成篮
|
* [904.水果成篮](https://leetcode-cn.com/problems/fruit-into-baskets/)
|
||||||
* 76.最小覆盖子串
|
* [76.最小覆盖子串](https://leetcode-cn.com/problems/minimum-window-substring/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,6 +308,35 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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:
|
JavaScript:
|
||||||
|
|
||||||
递归版本
|
递归版本
|
||||||
|
@ -265,6 +265,54 @@ class Solution:
|
|||||||
else: return root
|
else: return root
|
||||||
```
|
```
|
||||||
Go:
|
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}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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:
|
||||||
```javascript
|
```javascript
|
||||||
var maxSlidingWindow = function (nums, k) {
|
var maxSlidingWindow = function (nums, k) {
|
||||||
|
@ -130,7 +130,27 @@ class Solution:
|
|||||||
return True
|
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:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func isAnagram(s string, t string) bool {
|
func isAnagram(s string, t string) bool {
|
||||||
if len(s)!=len(t){
|
if len(s)!=len(t){
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
输入:n = 13
|
输入:n = 13
|
||||||
输出:2
|
输出:2
|
||||||
解释:13 = 4 + 9
|
解释:13 = 4 + 9
|
||||||
|
|
||||||
提示:
|
提示:
|
||||||
* 1 <= n <= 10^4
|
* 1 <= n <= 10^4
|
||||||
|
|
||||||
@ -184,9 +184,89 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
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:
|
||||||
|
```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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,7 +130,20 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
||||||
```go
|
```go
|
||||||
|
@ -189,6 +189,21 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
示例 5:
|
示例 5:
|
||||||
输入:coins = [1], amount = 2
|
输入:coins = [1], amount = 2
|
||||||
输出:2
|
输出:2
|
||||||
|
|
||||||
提示:
|
提示:
|
||||||
|
|
||||||
* 1 <= coins.length <= 12
|
* 1 <= coins.length <= 12
|
||||||
@ -209,9 +209,100 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
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:
|
||||||
|
```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
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,6 +287,25 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ class Solution:
|
|||||||
# 假设对正整数 i 拆分出的第一个正整数是 j(1 <= j < i),则有以下两种方案:
|
# 假设对正整数 i 拆分出的第一个正整数是 j(1 <= j < i),则有以下两种方案:
|
||||||
# 1) 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
|
# 1) 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
|
||||||
# 2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
|
# 2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 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]))
|
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
|
||||||
return dp[n]
|
return dp[n]
|
||||||
```
|
```
|
||||||
|
@ -21,11 +21,10 @@ https://leetcode-cn.com/problems/reverse-string/
|
|||||||
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
|
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
|
||||||
|
|
||||||
示例 1:
|
示例 1:
|
||||||
|
|
||||||
输入:["h","e","l","l","o"]
|
输入:["h","e","l","l","o"]
|
||||||
输出:["o","l","l","e","h"]
|
输出:["o","l","l","e","h"]
|
||||||
示例 2:
|
|
||||||
|
|
||||||
|
示例 2:
|
||||||
输入:["H","a","n","n","a","h"]
|
输入:["H","a","n","n","a","h"]
|
||||||
输出:["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++
|
```C++
|
||||||
class Solution {
|
class Solution {
|
||||||
|
@ -118,7 +118,7 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python3
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
|
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
|
||||||
result_set = set()
|
result_set = set()
|
||||||
|
@ -138,20 +138,16 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def wiggleMaxLength(self, nums: List[int]) -> int:
|
def wiggleMaxLength(self, nums: List[int]) -> int:
|
||||||
#贪心 求波峰数量 + 波谷数量
|
preC,curC,res = 0,0,1 #题目里nums长度大于等于1,当长度为1时,其实到不了for循环里去,所以不用考虑nums长度
|
||||||
if len(nums)<=1:
|
|
||||||
return len(nums)
|
|
||||||
cur, pre = 0,0 #当前一对差值,前一对差值
|
|
||||||
count = 1#默认最右边有一个峰值
|
|
||||||
for i in range(len(nums) - 1):
|
for i in range(len(nums) - 1):
|
||||||
cur = nums[i+1] - nums[i]
|
curC = nums[i + 1] - nums[i]
|
||||||
if((cur>0 and pre<=0) or (cur<0 and pre>=0)):
|
if curC * preC <= 0 and curC !=0: #差值为0时,不算摆动
|
||||||
count += 1
|
res += 1
|
||||||
pre = cur
|
preC = curC #如果当前差值和上一个差值为一正一负时,才需要用当前差值替代上一个差值
|
||||||
return count
|
return res
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
@ -183,7 +183,23 @@ class Solution:
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
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]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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里面的字符构成,但是这里需要注意两点。
|
本题判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成,但是这里需要注意两点。
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ public:
|
|||||||
|
|
||||||
依然是数组在哈希法中的应用。
|
依然是数组在哈希法中的应用。
|
||||||
|
|
||||||
一些同学可能想,用数组干啥,都用map完事了,**其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数。 所以数组更加简单直接有效!**
|
一些同学可能想,用数组干啥,都用map完事了,**其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!**
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
@ -135,8 +135,52 @@ class Solution {
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python写法一(使用数组作为哈希表):
|
||||||
```py
|
|
||||||
|
```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):
|
class Solution(object):
|
||||||
def canConstruct(self, ransomNote, magazine):
|
def canConstruct(self, ransomNote, magazine):
|
||||||
"""
|
"""
|
||||||
@ -166,6 +210,7 @@ class Solution(object):
|
|||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func canConstruct(ransomNote string, magazine string) bool {
|
func canConstruct(ransomNote string, magazine string) bool {
|
||||||
record := make([]int, 26)
|
record := make([]int, 26)
|
||||||
|
@ -144,7 +144,20 @@ Java:
|
|||||||
|
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -226,6 +226,71 @@ class Solution:
|
|||||||
```
|
```
|
||||||
Go:
|
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:
|
||||||
递归版本
|
递归版本
|
||||||
```javascript
|
```javascript
|
||||||
@ -275,6 +340,7 @@ var sumOfLeftLeaves = function(root) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||||
|
@ -226,7 +226,25 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -228,7 +228,27 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -175,7 +175,24 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -120,7 +120,7 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
Python:
|
||||||
|
|
||||||
```
|
```python
|
||||||
class Solution(object):
|
class Solution(object):
|
||||||
def fourSumCount(self, nums1, nums2, nums3, nums4):
|
def fourSumCount(self, nums1, nums2, nums3, nums4):
|
||||||
"""
|
"""
|
||||||
@ -148,6 +148,30 @@ class Solution(object):
|
|||||||
count += hashmap[key]
|
count += hashmap[key]
|
||||||
return count
|
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方法会返回None(key不存在)或者key对应的value
|
||||||
|
# 所以如果value==0,就会继续执行or,count+0,否则就会直接加value
|
||||||
|
# 这样就不用去写if判断了
|
||||||
|
|
||||||
|
# count += value or 0
|
||||||
|
|
||||||
|
# return count
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -134,22 +134,17 @@ class Solution {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def findContentChildren(self, g: List[int], s: List[int]) -> int:
|
def findContentChildren(self, g: List[int], s: List[int]) -> int:
|
||||||
#先考虑胃口小的孩子
|
|
||||||
g.sort()
|
g.sort()
|
||||||
s.sort()
|
s.sort()
|
||||||
i=j=0
|
res = 0
|
||||||
count = 0
|
for i in range(len(s)):
|
||||||
while(i<len(g) and j<len(s)):
|
if res <len(g) and s[i] >= g[res]: #小饼干先喂饱小胃口
|
||||||
if g[i]<=s[j]:
|
res += 1
|
||||||
count+=1
|
return res
|
||||||
i+=1 #如果满足了,则继续遍历下一个孩子和下一块饼干
|
|
||||||
j += 1 #如果最小的饼干没有满足当前最小胃口的孩子,则遍历下一块饼干
|
|
||||||
return count
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
Javascript:
|
Javascript:
|
||||||
|
@ -206,7 +206,43 @@ class Solution:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -428,7 +428,100 @@ class Solution:
|
|||||||
return self.res
|
return self.res
|
||||||
```
|
```
|
||||||
Go:
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -298,6 +298,80 @@ class Solution:
|
|||||||
```
|
```
|
||||||
Go:
|
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:
|
JavaScript:
|
||||||
1. 递归版本
|
1. 递归版本
|
||||||
```javascript
|
```javascript
|
||||||
|
@ -170,7 +170,20 @@ public class Solution {
|
|||||||
|
|
||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
示例 3:
|
示例 3:
|
||||||
输入: amount = 10, coins = [10]
|
输入: amount = 10, coins = [10]
|
||||||
输出: 1
|
输出: 1
|
||||||
|
|
||||||
注意,你可以假设:
|
注意,你可以假设:
|
||||||
|
|
||||||
* 0 <= amount (总金额) <= 5000
|
* 0 <= amount (总金额) <= 5000
|
||||||
@ -101,7 +101,7 @@ dp[j] (考虑coins[i]的组合总和) 就是所有的dp[j - coins[i]](不
|
|||||||
|
|
||||||
而本题要求凑成总和的组合数,元素之间要求没有顺序。
|
而本题要求凑成总和的组合数,元素之间要求没有顺序。
|
||||||
|
|
||||||
所以纯完全背包是能凑成总结就行,不用管怎么凑的。
|
所以纯完全背包是能凑成总和就行,不用管怎么凑的。
|
||||||
|
|
||||||
本题是求凑出来的方案个数,且每个方案个数是为组合数。
|
本题是求凑出来的方案个数,且每个方案个数是为组合数。
|
||||||
|
|
||||||
@ -208,10 +208,42 @@ class Solution {
|
|||||||
Python:
|
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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -151,7 +151,30 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
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
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
TreeNode pre;// 记录上一个遍历的结点
|
TreeNode pre;// 记录上一个遍历的结点
|
||||||
@ -201,8 +224,37 @@ class Solution:
|
|||||||
return r
|
return r
|
||||||
```
|
```
|
||||||
Go:
|
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)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -38,7 +38,7 @@ https://leetcode-cn.com/problems/reverse-string-ii/
|
|||||||
**所以当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。**
|
**所以当需要固定规律一段一段去处理字符串的时候,要想想在在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来实现反转也没毛病,毕竟不是解题关键部分。
|
那么这里具体反转的逻辑我们要不要使用库函数呢,其实用不用都可以,使用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函数区间是左闭右闭区间,代码如下:
|
下面我实现的reverse函数区间是左闭右闭区间,代码如下:
|
||||||
|
|
||||||
@ -103,6 +103,7 @@ public:
|
|||||||
|
|
||||||
Java:
|
Java:
|
||||||
```Java
|
```Java
|
||||||
|
//解法一
|
||||||
class Solution {
|
class Solution {
|
||||||
public String reverseStr(String s, int k) {
|
public String reverseStr(String s, int k) {
|
||||||
StringBuffer res = new StringBuffer();
|
StringBuffer res = new StringBuffer();
|
||||||
@ -128,6 +129,28 @@ class Solution {
|
|||||||
return res.toString();
|
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:
|
Python:
|
||||||
|
@ -104,10 +104,47 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
||||||
|
```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:
|
Go:
|
||||||
|
|
||||||
|
@ -332,6 +332,43 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -284,6 +284,56 @@ class Solution {
|
|||||||
|
|
||||||
Python:
|
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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -278,6 +278,75 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,10 +156,65 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* 1.dp[i] 代表当前下表最大连续值
|
||||||
|
* 2.递推公式 if(nums[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:
|
||||||
|
|
||||||
|
> 动态规划:
|
||||||
|
```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:
|
Go:
|
||||||
|
|
||||||
|
@ -241,6 +241,56 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,16 +13,21 @@
|
|||||||
|
|
||||||
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
|
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
|
||||||
|
|
||||||
|
|
||||||
示例 1:
|
示例 1:
|
||||||
|
|
||||||
|
```
|
||||||
输入: nums = [-1,0,3,5,9,12], target = 9
|
输入: nums = [-1,0,3,5,9,12], target = 9
|
||||||
输出: 4
|
输出: 4
|
||||||
解释: 9 出现在 nums 中并且下标为 4
|
解释: 9 出现在 nums 中并且下标为 4
|
||||||
|
```
|
||||||
|
|
||||||
示例 2:
|
示例 2:
|
||||||
|
|
||||||
|
```
|
||||||
输入: nums = [-1,0,3,5,9,12], target = 2
|
输入: nums = [-1,0,3,5,9,12], target = 2
|
||||||
输出: -1
|
输出: -1
|
||||||
解释: 2 不存在 nums 中因此返回 -1
|
解释: 2 不存在 nums 中因此返回 -1
|
||||||
|
```
|
||||||
|
|
||||||
提示:
|
提示:
|
||||||
|
|
||||||
@ -146,7 +151,7 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
Java:
|
**Java:**
|
||||||
|
|
||||||
(版本一)左闭右闭区间
|
(版本一)左闭右闭区间
|
||||||
|
|
||||||
@ -192,9 +197,11 @@ class Solution {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
**Python:**
|
||||||
|
|
||||||
```python3
|
(版本一)左闭右闭区间
|
||||||
|
|
||||||
|
```python
|
||||||
class Solution:
|
class Solution:
|
||||||
def search(self, nums: List[int], target: int) -> int:
|
def search(self, nums: List[int], target: int) -> int:
|
||||||
left, right = 0, len(nums) - 1
|
left, right = 0, len(nums) - 1
|
||||||
@ -211,8 +218,26 @@ class Solution:
|
|||||||
return -1
|
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
|
```js
|
||||||
|
|
||||||
|
@ -158,6 +158,7 @@ private:
|
|||||||
|
|
||||||
Java:
|
Java:
|
||||||
```Java
|
```Java
|
||||||
|
//单链表
|
||||||
class ListNode {
|
class ListNode {
|
||||||
int val;
|
int val;
|
||||||
ListNode next;
|
ListNode next;
|
||||||
@ -236,10 +237,110 @@ class MyLinkedList {
|
|||||||
pred.next = pred.next.next;
|
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:
|
Python:
|
||||||
```python3
|
```python
|
||||||
# 单链表
|
# 单链表
|
||||||
class Node:
|
class Node:
|
||||||
|
|
||||||
|
@ -217,7 +217,29 @@ class Solution: # 贪心思路
|
|||||||
|
|
||||||
Go:
|
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
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -139,7 +139,17 @@ public int maxProfit(int[] prices, int fee) {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -154,10 +154,58 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
||||||
|
|
||||||
|
> 动态规划:
|
||||||
|
```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:
|
||||||
```Go
|
```Go
|
||||||
|
@ -147,23 +147,43 @@ class Solution {
|
|||||||
|
|
||||||
|
|
||||||
Python:
|
Python:
|
||||||
```python
|
```python3
|
||||||
class Solution:
|
class Solution:
|
||||||
def monotoneIncreasingDigits(self, n: int) -> int:
|
def monotoneIncreasingDigits(self, n: int) -> int:
|
||||||
strNum = list(str(n))
|
a = list(str(n))
|
||||||
flag = len(strNum)
|
for i in range(len(a)-1,0,-1):
|
||||||
for i in range(len(strNum) - 1, 0, -1):
|
if int(a[i]) < int(a[i-1]):
|
||||||
if int(strNum[i]) < int(strNum[i - 1]):
|
a[i-1] = str(int(a[i-1]) - 1)
|
||||||
strNum[i - 1] = str(int(strNum[i - 1]) - 1)
|
a[i:] = '9' * (len(a) - i) #python不需要设置flag值,直接按长度给9就好了
|
||||||
flag = i
|
return int("".join(a))
|
||||||
for i in range(flag, len(strNum)):
|
|
||||||
strNum[i] = '9'
|
|
||||||
return int("".join(strNum))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
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
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
271
problems/0739.每日温度.md
Normal file
271
problems/0739.每日温度.md
Normal 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]。
|
||||||
|
|
||||||
|
首先先将第一个遍历元素加入单调栈
|
||||||
|

|
||||||
|
|
||||||
|
加入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]。
|
||||||
|

|
||||||
|
|
||||||
|
加入T[2],同理,T[1]弹出
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
加入T[3],T[3] < T[2] (当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况),加T[3]加入单调栈。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
加入T[4],T[4] == T[3] (当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!
|
||||||
|

|
||||||
|
|
||||||
|
加入T[5],T[5] > T[4] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[4]弹出,同时计算距离,更新result
|
||||||
|

|
||||||
|
|
||||||
|
T[4]弹出之后, T[5] > T[3] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[3]继续弹出,同时计算距离,更新result
|
||||||
|

|
||||||
|
|
||||||
|
直到发现T[5]小于T[st.top()],终止弹出,将T[5]加入单调栈
|
||||||
|

|
||||||
|
|
||||||
|
加入T[6],同理,需要将栈里的T[5],T[2]弹出
|
||||||
|

|
||||||
|
|
||||||
|
同理,继续弹出
|
||||||
|

|
||||||
|
|
||||||
|
此时栈里只剩下了T[6]
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
加入T[7], T[7] < T[6] 直接入栈,这就是最后的情况,result数组也更新完了。
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
此时有同学可能就疑惑了,那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>
|
||||||
|
|
@ -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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -128,7 +128,26 @@ class Solution:
|
|||||||
|
|
||||||
Go:
|
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
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -184,7 +184,38 @@ class Solution:
|
|||||||
Go:
|
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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -369,7 +369,42 @@ class Solution:
|
|||||||
```
|
```
|
||||||
Go:
|
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
|
||||||
|
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -96,8 +96,46 @@ public:
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
||||||
```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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -133,11 +133,35 @@ class Solution:
|
|||||||
A[i] *= -1
|
A[i] *= -1
|
||||||
K -= 1
|
K -= 1
|
||||||
if K > 0:
|
if K > 0:
|
||||||
A[len(A) - 1] *= ((-1)**K)
|
A[-1] *= (-1)**K #取A最后一个数只需要写-1
|
||||||
return sum(A)
|
return sum(A)
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
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:
|
Javascript:
|
||||||
|
@ -93,7 +93,18 @@ Java:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -257,9 +257,190 @@ Java:
|
|||||||
|
|
||||||
Python:
|
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:
|
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]//回溯
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ class Solution:
|
|||||||
Go:
|
Go:
|
||||||
|
|
||||||
前序遍历:
|
前序遍历:
|
||||||
```
|
```go
|
||||||
func PreorderTraversal(root *TreeNode) (res []int) {
|
func PreorderTraversal(root *TreeNode) (res []int) {
|
||||||
var traversal func(node *TreeNode)
|
var traversal func(node *TreeNode)
|
||||||
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) {
|
func InorderTraversal(root *TreeNode) (res []int) {
|
||||||
var traversal func(node *TreeNode)
|
var traversal func(node *TreeNode)
|
||||||
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) {
|
func PostorderTraversal(root *TreeNode) (res []int) {
|
||||||
var traversal func(node *TreeNode)
|
var traversal func(node *TreeNode)
|
||||||
traversal = func(node *TreeNode) {
|
traversal = func(node *TreeNode) {
|
||||||
|
@ -42,9 +42,9 @@ i指向新长度的末尾,j指向旧长度的末尾。
|
|||||||
|
|
||||||
时间复杂度,空间复杂度均超过100%的用户。
|
时间复杂度,空间复杂度均超过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++
|
```C++
|
||||||
class Solution {
|
class Solution {
|
||||||
@ -76,17 +76,17 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
```
|
```
|
||||||
时间复杂度:O(n)
|
* 时间复杂度:O(n)
|
||||||
空间复杂度:O(1)
|
* 空间复杂度:O(1)
|
||||||
|
|
||||||
此时算上本题,我们已经做了七道双指针相关的题目了分别是:
|
此时算上本题,我们已经做了七道双指针相关的题目了分别是:
|
||||||
|
|
||||||
* [27.移除元素](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA)
|
* [27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)
|
||||||
* [15.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A)
|
* [15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)
|
||||||
* [18.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)
|
* [18.四数之和](https://mp.weixin.qq.com/s/SBU3THi1Kv6Sar7htqCB2Q)
|
||||||
* [206.翻转链表](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)
|
* [206.翻转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)
|
||||||
* [142.环形链表II](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)
|
* [142.环形链表II](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)
|
||||||
* [344.反转字符串](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA)
|
* [344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)
|
||||||
|
|
||||||
# 拓展
|
# 拓展
|
||||||
|
|
||||||
@ -121,10 +121,6 @@ for (int i = 0; i < a.size(); i++) {
|
|||||||
所以想处理字符串,我们还是会定义一个string类型。
|
所以想处理字符串,我们还是会定义一个string类型。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
@ -150,11 +146,56 @@ public static String replaceSpace(StringBuffer str) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Python:
|
|
||||||
|
|
||||||
|
|
||||||
Go:
|
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)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
最终得到左旋2个单元的字符串:cdefgab
|
||||||
|
|
||||||
思路明确之后,那么代码实现就很简单了
|
思路明确之后,那么代码实现就很简单了
|
||||||
|
|
||||||
# C++代码
|
C++代码如下:
|
||||||
|
|
||||||
```C++
|
```C++
|
||||||
class Solution {
|
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:
|
Java:
|
||||||
@ -117,7 +117,6 @@ class Solution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Python:
|
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
|
|
||||||
|
@ -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(集合)
|
* set(集合)
|
||||||
* map(映射)
|
* 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,都是很有考究的。
|
例如什么时候用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不就完事了。
|
一些同学可能想,用数组干啥,都用map不就完事了。
|
||||||
|
|
||||||
@ -56,7 +55,7 @@
|
|||||||
|
|
||||||
## set作为哈希表
|
## set作为哈希表
|
||||||
|
|
||||||
在[哈希表:两个数组的交集](https://mp.weixin.qq.com/s/N9iqAchXreSVW7zXUS4BVA)中我们给出了什么时候用数组就不行了,需要用set。
|
在[349. 两个数组的交集](https://mp.weixin.qq.com/s/aMSA5zrp3jJcLjuSB0Es2Q)中我们给出了什么时候用数组就不行了,需要用set。
|
||||||
|
|
||||||
这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
|
这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
|
||||||
|
|
||||||
@ -67,7 +66,7 @@
|
|||||||
|
|
||||||
所以此时一样的做映射的话,就可以使用set了。
|
所以此时一样的做映射的话,就可以使用set了。
|
||||||
|
|
||||||
关于set,C++ 给提供了如下三种可用的数据结构:(详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA))
|
关于set,C++ 给提供了如下三种可用的数据结构:(详情请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg))
|
||||||
|
|
||||||
* std::set
|
* std::set
|
||||||
* std::multiset
|
* std::multiset
|
||||||
@ -75,12 +74,12 @@
|
|||||||
|
|
||||||
std::set和std::multiset底层实现都是红黑树,std::unordered_set的底层实现是哈希, 使用unordered_set 读写效率是最高的,本题并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set。
|
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作为哈希表
|
## map作为哈希表
|
||||||
|
|
||||||
在[哈希表:两数之和](https://mp.weixin.qq.com/s/uVAtjOHSeqymV8FeQbliJQ)中map正式登场。
|
在[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)中map正式登场。
|
||||||
|
|
||||||
来说一说:使用数组和set来做哈希法的局限。
|
来说一说:使用数组和set来做哈希法的局限。
|
||||||
|
|
||||||
@ -89,7 +88,7 @@ std::set和std::multiset底层实现都是红黑树,std::unordered_set的底
|
|||||||
|
|
||||||
map是一种`<key, value>`的结构,本题可以用key保存数值,用value在保存数值所在的下表。所以使用map最为合适。
|
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::map
|
||||||
* std::multimap
|
* std::multimap
|
||||||
@ -97,21 +96,21 @@ C++提供如下三种map::(详情请看[关于哈希表,你该了解这
|
|||||||
|
|
||||||
std::unordered_map 底层实现为哈希,std::map 和std::multimap 的底层实现是红黑树。
|
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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -85,20 +85,7 @@ std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
|
|||||||
|
|
||||||
所以STL 队列也不被归类为容器,而被归类为container adapter( 容器适配器)。
|
所以STL 队列也不被归类为容器,而被归类为container adapter( 容器适配器)。
|
||||||
|
|
||||||
我这里讲的都是(clck)C++ 语言中情况, 使用其他语言的同学也要思考栈与队列的底层实现问题, 不要对数据结构的使用浅尝辄止,而要深挖起内部原理,才能夯实基础。
|
我这里讲的都是C++ 语言中情况, 使用其他语言的同学也要思考栈与队列的底层实现问题, 不要对数据结构的使用浅尝辄止,而要深挖起内部原理,才能夯实基础。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
|
||||||
|
|
||||||
|
|
||||||
Java:
|
|
||||||
|
|
||||||
|
|
||||||
Python:
|
|
||||||
|
|
||||||
|
|
||||||
Go:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -265,15 +265,120 @@ int main() {
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
|
|
||||||
Java:
|
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:
|
||||||
|
```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:
|
||||||
|
```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)
|
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||||
</p>
|
</p>
|
||||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||||
|
|
||||||
# 动态规划:关于01背包问题,你该了解这些!(滚动数组)
|
# 动态规划:关于01背包问题,你该了解这些!(滚动数组)
|
||||||
|
|
||||||
昨天[动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中是用二维dp数组来讲解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[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:
|
||||||
|
|
||||||
|
```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:
|
||||||
|
```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:
|
||||||
|
```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)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,9 +147,56 @@ int main() {
|
|||||||
|
|
||||||
Java:
|
Java:
|
||||||
|
|
||||||
|
|
||||||
Python:
|
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:
|
Go:
|
||||||
|
|
||||||
|
@ -220,7 +220,58 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
|
|
||||||
Go:
|
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))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,11 +32,11 @@
|
|||||||
|
|
||||||
看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:
|
看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:
|
||||||
|
|
||||||
v
|

|
||||||
|
|
||||||
我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图:
|
我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到焦点。
|
此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到焦点。
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user