mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-12 21:50:49 +08:00
Merge branch 'master' into 583-minDistance
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
.idea/
|
||||
.DS_Store
|
||||
.vscode
|
||||
.temp
|
||||
.cache
|
||||
*.iml
|
||||
__pycache__
|
@ -106,8 +106,8 @@
|
||||
4. [数组:977.有序数组的平方](./problems/0977.有序数组的平方.md)
|
||||
5. [数组:209.长度最小的子数组](./problems/0209.长度最小的子数组.md)
|
||||
6. [数组:区间和](./problems/kamacoder/0058.区间和.md)
|
||||
6. [数组:59.螺旋矩阵II](./problems/0059.螺旋矩阵II.md)
|
||||
8. [数组:开发商购买土地](./problems/kamacoder/0044.开发商购买土地.md)
|
||||
7. [数组:开发商购买土地](./problems/kamacoder/0044.开发商购买土地.md)
|
||||
8. [数组:59.螺旋矩阵II](./problems/0059.螺旋矩阵II.md)
|
||||
9. [数组:总结篇](./problems/数组总结篇.md)
|
||||
|
||||
## 链表
|
||||
@ -196,7 +196,6 @@
|
||||
12. [二叉树:110.平衡二叉树](./problems/0110.平衡二叉树.md)
|
||||
13. [二叉树:257.二叉树的所有路径](./problems/0257.二叉树的所有路径.md)
|
||||
14. [本周总结!(二叉树)](./problems/周总结/20201003二叉树周末总结.md)
|
||||
15. [二叉树:二叉树中递归带着回溯](./problems/二叉树中递归带着回溯.md)
|
||||
16. [二叉树:404.左叶子之和](./problems/0404.左叶子之和.md)
|
||||
17. [二叉树:513.找树左下角的值](./problems/0513.找树左下角的值.md)
|
||||
18. [二叉树:112.路径总和](./problems/0112.路径总和.md)
|
||||
@ -400,7 +399,7 @@
|
||||
24. [图论:Bellman_ford 算法](./problems/kamacoder/0094.城市间货物运输I.md)
|
||||
25. [图论:Bellman_ford 队列优化算法(又名SPFA)](./problems/kamacoder/0094.城市间货物运输I-SPFA.md)
|
||||
26. [图论:Bellman_ford之判断负权回路](./problems/kamacoder/0095.城市间货物运输II.md)
|
||||
27. [图论:Bellman_ford之单源有限最短路](./problems/kamacoder/0095.城市间货物运输II.md)
|
||||
27. [图论:Bellman_ford之单源有限最短路](./problems/kamacoder/0096.城市间货物运输III.md)
|
||||
28. [图论:Floyd 算法](./problems/kamacoder/0097.小明逛公园.md)
|
||||
29. [图论:A * 算法](./problems/kamacoder/0126.骑士的攻击astar.md)
|
||||
30. [图论:最短路算法总结篇](./problems/kamacoder/最短路问题总结篇.md)
|
||||
|
@ -341,7 +341,7 @@ impl Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
var twoSum = function (nums, target) {
|
||||
|
@ -275,7 +275,7 @@ def is_valid(strs)
|
||||
end
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
var isValid = function (s) {
|
||||
|
@ -286,7 +286,7 @@ func swapPairs(head *ListNode) *ListNode {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
var swapPairs = function (head) {
|
||||
|
@ -131,7 +131,24 @@ public:
|
||||
## 其他语言版本
|
||||
|
||||
### Java:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public int removeElement(int[] nums, int val) {
|
||||
// 暴力法
|
||||
int n = nums.length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (nums[i] == val) {
|
||||
for (int j = i + 1; j < n; j++) {
|
||||
nums[j - 1] = nums[j];
|
||||
}
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
```
|
||||
```java
|
||||
class Solution {
|
||||
public int removeElement(int[] nums, int val) {
|
||||
|
@ -460,7 +460,7 @@ func isvalid(row, col int, k byte, board [][]byte) bool {
|
||||
|
||||
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var solveSudoku = function(board) {
|
||||
|
@ -374,7 +374,7 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var jump = function(nums) {
|
||||
|
@ -201,6 +201,7 @@ class Solution {
|
||||
public void backtrack(int[] nums, LinkedList<Integer> path) {
|
||||
if (path.size() == nums.length) {
|
||||
result.add(new ArrayList<>(path));
|
||||
return;
|
||||
}
|
||||
for (int i =0; i < nums.length; i++) {
|
||||
// 如果path中已有,则跳过
|
||||
@ -271,7 +272,7 @@ func dfs(nums []int, cur int) {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```js
|
||||
|
||||
@ -524,3 +525,4 @@ public class Solution
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
@ -283,7 +283,7 @@ func dfs(nums []int, cur int) {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```javascript
|
||||
var permuteUnique = function (nums) {
|
||||
|
@ -451,7 +451,7 @@ func isValid(n, row, col int, chessboard [][]string) bool {
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
/**
|
||||
* @param {number} n
|
||||
|
@ -240,6 +240,42 @@ class Solution:
|
||||
res = max(res, dp[i])
|
||||
return res
|
||||
```
|
||||
|
||||
动态规划
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def maxSubArray(self, nums):
|
||||
if not nums:
|
||||
return 0
|
||||
dp = [0] * len(nums) # dp[i]表示包括i之前的最大连续子序列和
|
||||
dp[0] = nums[0]
|
||||
result = dp[0]
|
||||
for i in range(1, len(nums)):
|
||||
dp[i] = max(dp[i-1]+nums[i], nums[i]) # 状态转移公式
|
||||
if dp[i] > result:
|
||||
result = dp[i] # result 保存dp[i]的最大值
|
||||
return result
|
||||
```
|
||||
|
||||
动态规划优化
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def maxSubArray(self, nums: List[int]) -> int:
|
||||
max_sum = float("-inf") # 初始化结果为负无穷大,方便比较取最大值
|
||||
current_sum = 0 # 初始化当前连续和
|
||||
|
||||
for num in nums:
|
||||
|
||||
# 更新当前连续和
|
||||
# 如果原本的连续和加上当前数字之后没有当前数字大,说明原本的连续和是负数,那么就直接从当前数字开始重新计算连续和
|
||||
current_sum = max(current_sum+num, num)
|
||||
max_sum = max(max_sum, current_sum) # 更新结果
|
||||
|
||||
return max_sum
|
||||
```
|
||||
|
||||
### Go
|
||||
贪心法
|
||||
```go
|
||||
@ -290,7 +326,7 @@ pub fn max_sub_array(nums: Vec<i32>) -> i32 {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```Javascript
|
||||
var maxSubArray = function(nums) {
|
||||
|
@ -260,7 +260,7 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```
|
||||
/**
|
||||
* @param {number[][]} matrix
|
||||
|
@ -143,6 +143,23 @@ class Solution:
|
||||
return False
|
||||
```
|
||||
|
||||
```python
|
||||
## 基于当前最远可到达位置判断
|
||||
class Solution:
|
||||
def canJump(self, nums: List[int]) -> bool:
|
||||
far = nums[0]
|
||||
for i in range(len(nums)):
|
||||
# 要考虑两个情况
|
||||
# 1. i <= far - 表示 当前位置i 可以到达
|
||||
# 2. i > far - 表示 当前位置i 无法到达
|
||||
if i > far:
|
||||
return False
|
||||
far = max(far, nums[i]+i)
|
||||
# 如果循环正常结束,表示最后一个位置也可以到达,否则会在中途直接退出
|
||||
# 关键点在于,要想明白其实列表中的每个位置都是需要验证能否到达的
|
||||
return True
|
||||
```
|
||||
|
||||
### Go
|
||||
|
||||
```go
|
||||
@ -166,7 +183,7 @@ func max(a, b int ) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var canJump = function(nums) {
|
||||
|
@ -215,7 +215,7 @@ func max56(a, b int) int {
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```javascript
|
||||
var merge = function (intervals) {
|
||||
intervals.sort((a, b) => a[0] - b[0]);
|
||||
|
@ -411,7 +411,7 @@ func uniquePaths(m int, n int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var uniquePaths = function(m, n) {
|
||||
|
@ -465,7 +465,7 @@ func uniquePathsWithObstacles(obstacleGrid [][]int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var uniquePathsWithObstacles = function(obstacleGrid) {
|
||||
|
@ -327,7 +327,7 @@ func climbStairs(n int) int {
|
||||
return dp[n]
|
||||
}
|
||||
```
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var climbStairs = function(n) {
|
||||
// dp[i] 为第 i 阶楼梯有多少种方法爬到楼顶
|
||||
|
@ -313,7 +313,7 @@ func Min(args ...int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
const minDistance = (word1, word2) => {
|
||||
|
@ -468,7 +468,7 @@ func dfs(n int, k int, start int) {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
未剪枝:
|
||||
|
||||
```js
|
||||
|
@ -246,7 +246,7 @@ func dfs(nums []int, start int) {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var subsets = function(nums) {
|
||||
|
@ -376,7 +376,7 @@ func dfs(nums []int, start int) {
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
|
||||
|
@ -376,9 +376,8 @@ class Solution {
|
||||
// 剪枝:ip段的长度最大是3,并且ip段处于[0,255]
|
||||
for (int i = start; i < s.length() && i - start < 3 && Integer.parseInt(s.substring(start, i + 1)) >= 0
|
||||
&& Integer.parseInt(s.substring(start, i + 1)) <= 255; i++) {
|
||||
// 如果ip段的长度大于1,并且第一位为0的话,continue
|
||||
if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
stringBuilder.append(s.substring(start, i + 1));
|
||||
// 当stringBuilder里的网段数量小于3时,才会加点;如果等于3,说明已经有3段了,最后一段不需要再加点
|
||||
|
@ -221,7 +221,7 @@ func numTrees(n int)int{
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
const numTrees =(n) => {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
## 算法公开课
|
||||
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
## 思路
|
||||
|
@ -356,7 +356,7 @@ func levelOrder(root *TreeNode) (res [][]int) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Javascript:
|
||||
#### JavaScript:
|
||||
|
||||
```javascript
|
||||
var levelOrder = function(root) {
|
||||
@ -759,7 +759,7 @@ func levelOrderBottom(root *TreeNode) [][]int {
|
||||
}
|
||||
```
|
||||
|
||||
#### Javascript:
|
||||
#### JavaScript:
|
||||
|
||||
```javascript
|
||||
var levelOrderBottom = function (root) {
|
||||
@ -1101,7 +1101,7 @@ func rightSideView(root *TreeNode) []int {
|
||||
}
|
||||
```
|
||||
|
||||
#### Javascript:
|
||||
#### JavaScript:
|
||||
|
||||
```javascript
|
||||
var rightSideView = function(root) {
|
||||
@ -1421,7 +1421,7 @@ func averageOfLevels(root *TreeNode) []float64 {
|
||||
}
|
||||
```
|
||||
|
||||
#### Javascript:
|
||||
#### JavaScript:
|
||||
|
||||
```javascript
|
||||
var averageOfLevels = function(root) {
|
||||
@ -2109,7 +2109,7 @@ func largestValues(root *TreeNode) []int {
|
||||
}
|
||||
```
|
||||
|
||||
#### Javascript:
|
||||
#### JavaScript:
|
||||
|
||||
```javascript
|
||||
var largestValues = function (root) {
|
||||
|
@ -604,7 +604,7 @@ func maxDepth(root *Node) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript :
|
||||
### JavaScript :
|
||||
|
||||
104.二叉树的最大深度
|
||||
|
||||
|
@ -830,7 +830,7 @@ func traverse(node *TreeNode, result *[][]int, currPath *[]int, targetSum int) {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
0112.路径总和
|
||||
|
||||
|
@ -265,7 +265,7 @@ func numDistinct(s string, t string) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
const numDistinct = (s, t) => {
|
||||
|
@ -249,7 +249,7 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
贪心
|
||||
|
||||
|
@ -251,6 +251,27 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// 动态规划 版本二 滚动数组
|
||||
func maxProfit(prices []int) int {
|
||||
dp := [2][2]int{} // 注意这里只开辟了一个2 * 2大小的二维数组
|
||||
dp[0][0] = -prices[0]
|
||||
dp[0][1] = 0
|
||||
for i := 1; i < len(prices); i++ {
|
||||
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[(len(prices)-1)%2][1]
|
||||
}
|
||||
|
||||
func max(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
```
|
||||
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
|
@ -316,6 +316,8 @@ class Solution:
|
||||
|
||||
### Go:
|
||||
|
||||
> 版本一
|
||||
|
||||
```go
|
||||
func maxProfit(prices []int) int {
|
||||
dp := make([][]int, len(prices))
|
||||
@ -344,6 +346,80 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
> 版本二
|
||||
|
||||
```go
|
||||
func maxProfit(prices []int) int {
|
||||
if len(prices) == 0 {
|
||||
return 0
|
||||
}
|
||||
dp := make([]int, 5)
|
||||
dp[1] = -prices[0]
|
||||
dp[3] = -prices[0]
|
||||
for i := 1; i < len(prices); i++ {
|
||||
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]
|
||||
}
|
||||
|
||||
func max(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
```
|
||||
|
||||
> 版本三
|
||||
|
||||
```go
|
||||
func maxProfit(prices []int) int {
|
||||
if len(prices) == 0 {
|
||||
return 0
|
||||
}
|
||||
dp := make([][5]int, len(prices))
|
||||
dp[0][1] = -prices[0]
|
||||
dp[0][3] = -prices[0]
|
||||
for i := 1; i < len(prices); i++ {
|
||||
dp[i][1] = max(dp[i-1][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[len(prices)-1][4]
|
||||
}
|
||||
|
||||
func max(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
```
|
||||
|
||||
> 版本四:一维 dp 易懂版本
|
||||
|
||||
```go
|
||||
func maxProfit(prices []int) int {
|
||||
dp := make([]int, 4)
|
||||
dp[0] = -prices[0]
|
||||
dp[2] = -prices[0]
|
||||
|
||||
for _, price := range prices[1:] {
|
||||
dc := slices.Clone(dp) // 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp,逻辑简单易懂
|
||||
dp[0] = max(dc[0], -price)
|
||||
dp[1] = max(dc[1], dc[0] + price)
|
||||
dp[2] = max(dc[2], dc[1] - price)
|
||||
dp[3] = max(dc[3], dc[2] + price)
|
||||
}
|
||||
|
||||
return dp[3]
|
||||
}
|
||||
```
|
||||
|
||||
### JavaScript:
|
||||
|
||||
> 版本一:
|
||||
|
@ -396,7 +396,7 @@ func canCompleteCircuit(gas []int, cost []int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
暴力:
|
||||
```js
|
||||
var canCompleteCircuit = function(gas, cost) {
|
||||
|
@ -177,21 +177,20 @@ class Solution {
|
||||
```python
|
||||
class Solution:
|
||||
def candy(self, ratings: List[int]) -> int:
|
||||
candyVec = [1] * len(ratings)
|
||||
n = len(ratings)
|
||||
candies = [1] * n
|
||||
|
||||
# 从前向后遍历,处理右侧比左侧评分高的情况
|
||||
for i in range(1, len(ratings)):
|
||||
# Forward pass: handle cases where right rating is higher than left
|
||||
for i in range(1, n):
|
||||
if ratings[i] > ratings[i - 1]:
|
||||
candyVec[i] = candyVec[i - 1] + 1
|
||||
candies[i] = candies[i - 1] + 1
|
||||
|
||||
# 从后向前遍历,处理左侧比右侧评分高的情况
|
||||
for i in range(len(ratings) - 2, -1, -1):
|
||||
# Backward pass: handle cases where left rating is higher than right
|
||||
for i in range(n - 2, -1, -1):
|
||||
if ratings[i] > ratings[i + 1]:
|
||||
candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1)
|
||||
candies[i] = max(candies[i], candies[i + 1] + 1)
|
||||
|
||||
# 统计结果
|
||||
result = sum(candyVec)
|
||||
return result
|
||||
return sum(candies)
|
||||
|
||||
```
|
||||
|
||||
@ -234,7 +233,7 @@ func findMax(num1 int, num2 int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var candy = function(ratings) {
|
||||
let candys = new Array(ratings.length).fill(1)
|
||||
|
@ -108,7 +108,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int result = st.top();
|
||||
long long result = st.top();
|
||||
st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
|
||||
return result;
|
||||
}
|
||||
|
@ -513,6 +513,29 @@ class Solution:
|
||||
|
||||
return "".join(result)
|
||||
```
|
||||
|
||||
(版本五) 遇到空格就说明前面的是一个单词,把它加入到一个数组中。
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def reverseWords(self, s: str) -> str:
|
||||
words = []
|
||||
word = ''
|
||||
s += ' ' # 帮助处理最后一个字词
|
||||
|
||||
for char in s:
|
||||
if char == ' ': # 遇到空格就说明前面的可能是一个单词
|
||||
if word != '': # 确认是单词,把它加入到一个数组中
|
||||
words.append(word)
|
||||
word = '' # 清空当前单词
|
||||
continue
|
||||
|
||||
word += char # 收集单词的字母
|
||||
|
||||
words.reverse()
|
||||
return ' '.join(words)
|
||||
```
|
||||
|
||||
### Go:
|
||||
|
||||
版本一:
|
||||
|
@ -297,8 +297,7 @@ class Solution {
|
||||
|
||||
### Python:
|
||||
|
||||
版本一
|
||||
|
||||
> 版本一
|
||||
```python
|
||||
class Solution:
|
||||
def maxProfit(self, k: int, prices: List[int]) -> int:
|
||||
@ -313,7 +312,8 @@ class Solution:
|
||||
dp[i][j+2] = max(dp[i-1][j+2], dp[i-1][j+1] + prices[i])
|
||||
return dp[-1][2*k]
|
||||
```
|
||||
版本二
|
||||
|
||||
> 版本二
|
||||
```python
|
||||
class Solution:
|
||||
def maxProfit(self, k: int, prices: List[int]) -> int:
|
||||
@ -329,9 +329,31 @@ class Solution:
|
||||
dp[j] = max(dp[j],dp[j-1]+prices[i])
|
||||
return dp[2*k]
|
||||
```
|
||||
|
||||
> 版本三: 一维 dp 数组(易理解版本)
|
||||
```python
|
||||
class Solution:
|
||||
def maxProfit(self, k: int, prices: List[int]) -> int:
|
||||
dp = [0] * k * 2
|
||||
for i in range(k):
|
||||
dp[i * 2] = -prices[0]
|
||||
|
||||
for price in prices[1:]:
|
||||
dc = dp.copy() # 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp,逻辑简单易懂
|
||||
|
||||
for i in range(2 * k):
|
||||
if i % 2 == 1:
|
||||
dp[i] = max(dc[i], dc[i - 1] + price)
|
||||
else:
|
||||
pre = 0 if i == 0 else dc[i - 1]
|
||||
dp[i] = max(dc[i], pre - price)
|
||||
|
||||
return dp[-1]
|
||||
```
|
||||
|
||||
### Go:
|
||||
|
||||
版本一:
|
||||
> 版本一:
|
||||
|
||||
```go
|
||||
// 买卖股票的最佳时机IV 动态规划
|
||||
@ -368,7 +390,7 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
版本二: 三维 dp数组
|
||||
> 版本二: 三维 dp数组
|
||||
```go
|
||||
func maxProfit(k int, prices []int) int {
|
||||
length := len(prices)
|
||||
@ -443,7 +465,31 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
> 版本四:一维 dp 数组(易理解版本)
|
||||
|
||||
```go
|
||||
func maxProfit(k int, prices []int) int {
|
||||
dp := make([]int, 2 * k)
|
||||
for i := range k {
|
||||
dp[i * 2] = -prices[0]
|
||||
}
|
||||
|
||||
for j := 1; j < len(prices); j++ {
|
||||
dc := slices.Clone(dp) // 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp,逻辑简单易懂
|
||||
|
||||
for i := range k * 2 {
|
||||
if i % 2 == 1 {
|
||||
dp[i] = max(dc[i], dc[i - 1] + prices[j])
|
||||
} else {
|
||||
pre := 0; if i >= 1 { pre = dc[i - 1] }
|
||||
dp[i] = max(dc[i], pre - prices[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[2 * k - 1]
|
||||
}
|
||||
```
|
||||
|
||||
### JavaScript:
|
||||
|
||||
|
@ -199,7 +199,17 @@ function reverseByRange(nums: number[], left: number, right: number): void {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Rust
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn rotate(nums: &mut Vec<i32>, k: i32) {
|
||||
let k = k as usize % nums.len();
|
||||
nums.reverse();
|
||||
nums[..k].reverse();
|
||||
nums[k..].reverse();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
|
@ -534,6 +534,30 @@ public class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### Ruby:
|
||||
|
||||
```ruby
|
||||
# @param {Integer} n
|
||||
# @return {Boolean}
|
||||
def is_happy(n)
|
||||
@occurred_nums = Set.new
|
||||
|
||||
while true
|
||||
n = next_value(n)
|
||||
|
||||
return true if n == 1
|
||||
|
||||
return false if @occurred_nums.include?(n)
|
||||
|
||||
@occurred_nums << n
|
||||
end
|
||||
end
|
||||
|
||||
def next_value(n)
|
||||
n.to_s.chars.sum { |char| char.to_i ** 2 }
|
||||
end
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -737,7 +737,45 @@ public class Solution
|
||||
}
|
||||
}
|
||||
```
|
||||
### Ruby#
|
||||
|
||||
```ruby
|
||||
# 定义链表节点
|
||||
class ListNode
|
||||
attr_accessor :val, :next
|
||||
def initialize(val = 0, _next = nil)
|
||||
@val = val
|
||||
@next = _next
|
||||
end
|
||||
end
|
||||
|
||||
# 删除链表中值为 val 的节点
|
||||
def remove_elements(head, val)
|
||||
# 创建一个虚拟头节点,这样可以简化删除头节点的处理
|
||||
# 虚拟头节点的值为 0,指向当前链表的头节点
|
||||
dummy = ListNode.new(0)
|
||||
dummy.next = head
|
||||
|
||||
# 初始化当前节点为虚拟头节点
|
||||
current = dummy
|
||||
|
||||
# 遍历链表,直到当前节点的下一个节点为空
|
||||
while current.next
|
||||
# 如果当前节点的下一个节点的值等于 val
|
||||
if current.next.val == val
|
||||
# 跳过该节点,即将当前节点的 next 指向下一个节点的 next
|
||||
current.next = current.next.next
|
||||
else
|
||||
# 否则继续遍历,当前节点向前移动
|
||||
current = current.next
|
||||
end
|
||||
end
|
||||
|
||||
# 返回删除 val 后的新链表的头节点,虚拟头节点的 next 就是新的头节点
|
||||
dummy.next
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
@ -266,7 +266,7 @@ var minSubArrayLen = function(target, nums) {
|
||||
};
|
||||
```
|
||||
|
||||
### Typescript:
|
||||
### TypeScript:
|
||||
|
||||
```typescript
|
||||
function minSubArrayLen(target: number, nums: number[]): number {
|
||||
|
@ -113,7 +113,7 @@ public:
|
||||
|
||||
```
|
||||
|
||||
* 时间复杂度: push和empty为O(1), pop和peek为O(n)
|
||||
* 时间复杂度: 都为O(1)。pop和peek看起来像O(n),实际上一个循环n会被使用n次,最后还是O(1)。
|
||||
* 空间复杂度: O(n)
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
## 算法公开课
|
||||
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先](https://www.bilibili.com/video/BV1Zt4y1F7ww?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先](https://www.bilibili.com/video/BV1Zt4y1F7ww?share_source=copy_web),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
## 思路
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
## 算法公开课
|
||||
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
## 思路
|
||||
|
@ -299,7 +299,7 @@ class Solution {
|
||||
```
|
||||
|
||||
### Python:
|
||||
|
||||
#### 解法一:使用自定义的单调队列类
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
@ -339,6 +339,35 @@ class Solution:
|
||||
return result
|
||||
```
|
||||
|
||||
|
||||
#### 解法二:直接用单调队列
|
||||
```python
|
||||
from collections import deque
|
||||
class Solution:
|
||||
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
|
||||
max_list = [] # 结果集合
|
||||
kept_nums = deque() # 单调队列
|
||||
|
||||
for i in range(len(nums)):
|
||||
update_kept_nums(kept_nums, nums[i]) # 右侧新元素加入
|
||||
|
||||
if i >= k and nums[i - k] == kept_nums[0]: # 左侧旧元素如果等于单调队列头元素,需要移除头元素
|
||||
kept_nums.popleft()
|
||||
|
||||
if i >= k - 1:
|
||||
max_list.append(kept_nums[0])
|
||||
|
||||
return max_list
|
||||
|
||||
def update_kept_nums(kept_nums, num): # num 是新加入的元素
|
||||
# 所有小于新元素的队列尾部元素,在新元素出现后,都是没有价值的,都需要被移除
|
||||
while kept_nums and num > kept_nums[-1]:
|
||||
kept_nums.pop()
|
||||
|
||||
kept_nums.append(num)
|
||||
|
||||
```
|
||||
|
||||
### Go:
|
||||
|
||||
```go
|
||||
@ -401,7 +430,7 @@ func maxSlidingWindow(nums []int, k int) []int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
|
@ -346,7 +346,7 @@ func min(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```Javascript
|
||||
// 先遍历物品,再遍历背包
|
||||
|
@ -169,7 +169,20 @@ void moveZeroes(int* nums, int numsSize){
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Rust
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn move_zeroes(nums: &mut Vec<i32>) {
|
||||
let mut slow = 0;
|
||||
for fast in 0..nums.len() {
|
||||
if nums[fast] != 0 {
|
||||
nums.swap(slow, fast);
|
||||
slow += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -248,7 +248,7 @@ func lengthOfLIS(nums []int ) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
const lengthOfLIS = (nums) => {
|
||||
|
@ -274,7 +274,7 @@ class Solution {
|
||||
```
|
||||
|
||||
### Python:
|
||||
版本一
|
||||
> 版本一
|
||||
|
||||
```python
|
||||
from typing import List
|
||||
@ -294,7 +294,8 @@ class Solution:
|
||||
return max(dp[n-1][3], dp[n-1][1], dp[n-1][2]) # 返回最后一天不持有股票的最大利润
|
||||
|
||||
```
|
||||
版本二
|
||||
|
||||
> 版本二
|
||||
```python
|
||||
class Solution:
|
||||
def maxProfit(self, prices: List[int]) -> int:
|
||||
@ -320,6 +321,36 @@ class Solution:
|
||||
return max(dp[-1][1], dp[-1][2])
|
||||
|
||||
```
|
||||
|
||||
> 版本三
|
||||
```python
|
||||
class Solution:
|
||||
def maxProfit(self, prices: List[int]) -> int:
|
||||
# 0: holding stocks
|
||||
# (1) keep holding stocks: dp[i][0] = dp[i - 1][0]
|
||||
# (2) buy stocks: dp[i][0] = dp[i - 1][1] - price, or dp[i - 1][3] - price
|
||||
# 1: keep no stocks: dp[i][1] = dp[i - 1][1]
|
||||
# 2: sell stocks: dp[i][2] = dp[i - 1][0] + price
|
||||
# 3: cooldown day: dp[i][3] = dp[i - 1][2]
|
||||
dp = [-prices[0], 0, 0, 0]
|
||||
|
||||
for price in prices[1:]:
|
||||
dc = dp.copy() # 这句话是关键,把前一天的 dp 状态保存下来,防止被覆盖掉,后面只用它,不用 dp,逻辑简单易懂
|
||||
dp[0] = max(
|
||||
dc[0],
|
||||
dc[1] - price,
|
||||
dc[3] - price
|
||||
)
|
||||
dp[1] = max(
|
||||
dc[1],
|
||||
dc[3]
|
||||
)
|
||||
dp[2] = dc[0] + price
|
||||
dp[3] = dc[2]
|
||||
|
||||
return max(dp)
|
||||
```
|
||||
|
||||
### Go:
|
||||
|
||||
```go
|
||||
@ -393,7 +424,7 @@ func max(a, b int) int {
|
||||
|
||||
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
> 不同的状态定义 感觉更容易理解些
|
||||
```javascript
|
||||
|
@ -427,7 +427,7 @@ impl Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
// 遍历物品
|
||||
|
@ -535,7 +535,7 @@ func findItinerary(tickets [][]string) []string {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
|
||||
|
@ -388,19 +388,96 @@ class Solution:
|
||||
|
||||
### Go
|
||||
|
||||
暴力递归
|
||||
|
||||
```go
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* type TreeNode struct {
|
||||
* Val int
|
||||
* Left *TreeNode
|
||||
* Right *TreeNode
|
||||
* }
|
||||
*/
|
||||
func rob(root *TreeNode) int {
|
||||
if root == nil {
|
||||
return 0
|
||||
}
|
||||
if root.Left == nil && root.Right == nil {
|
||||
return root.Val
|
||||
}
|
||||
// 偷父节点
|
||||
val1 := root.Val
|
||||
if root.Left != nil {
|
||||
val1 += rob(root.Left.Left) + rob(root.Left.Right) // 跳过root->left,相当于不考虑左孩子了
|
||||
}
|
||||
if root.Right != nil {
|
||||
val1 += rob(root.Right.Left) + rob(root.Right.Right) // 跳过root->right,相当于不考虑右孩子了
|
||||
}
|
||||
// 不偷父节点
|
||||
val2 := rob(root.Left) + rob(root.Right) // 考虑root的左右孩子
|
||||
return max(val1, val2)
|
||||
}
|
||||
|
||||
func max(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
```
|
||||
|
||||
记忆化递推
|
||||
|
||||
```go
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* type TreeNode struct {
|
||||
* Val int
|
||||
* Left *TreeNode
|
||||
* Right *TreeNode
|
||||
* }
|
||||
*/
|
||||
var umap = make(map[*TreeNode]int)
|
||||
|
||||
func rob(root *TreeNode) int {
|
||||
if root == nil {
|
||||
return 0
|
||||
}
|
||||
if root.Left == nil && root.Right == nil {
|
||||
return root.Val
|
||||
}
|
||||
if val, ok := umap[root]; ok {
|
||||
return val // 如果umap里已经有记录则直接返回
|
||||
}
|
||||
// 偷父节点
|
||||
val1 := root.Val
|
||||
if root.Left != nil {
|
||||
val1 += rob(root.Left.Left) + rob(root.Left.Right) // 跳过root->left,相当于不考虑左孩子了
|
||||
}
|
||||
if root.Right != nil {
|
||||
val1 += rob(root.Right.Left) + rob(root.Right.Right) // 跳过root->right,相当于不考虑右孩子了
|
||||
}
|
||||
// 不偷父节点
|
||||
val2 := rob(root.Left) + rob(root.Right) // 考虑root的左右孩子
|
||||
umap[root] = max(val1, val2) // umap记录一下结果
|
||||
return max(val1, val2)
|
||||
}
|
||||
|
||||
func max(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
```
|
||||
|
||||
动态规划
|
||||
|
||||
```go
|
||||
func rob(root *TreeNode) int {
|
||||
res := robTree(root)
|
||||
return max(res[0], res[1])
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
return slices.Max(res)
|
||||
}
|
||||
|
||||
func robTree(cur *TreeNode) []int {
|
||||
@ -414,7 +491,7 @@ func robTree(cur *TreeNode) []int {
|
||||
// 考虑去偷当前的屋子
|
||||
robCur := cur.Val + left[0] + right[0]
|
||||
// 考虑不去偷当前的屋子
|
||||
notRobCur := max(left[0], left[1]) + max(right[0], right[1])
|
||||
notRobCur := slices.Max(left) + slices.Max(right)
|
||||
|
||||
// 注意顺序:0:不偷,1:去偷
|
||||
return []int{notRobCur, robCur}
|
||||
|
@ -385,7 +385,7 @@ func integerBreak(n int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var integerBreak = function(n) {
|
||||
let dp = new Array(n + 1).fill(0)
|
||||
|
@ -466,7 +466,7 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
**贪心**
|
||||
|
||||
|
@ -254,7 +254,7 @@ func combinationSum4(nums []int, target int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
const combinationSum4 = (nums, target) => {
|
||||
|
@ -270,7 +270,7 @@ func reconstructQueue(people [][]int) [][]int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var reconstructQueue = function(people) {
|
||||
|
@ -47,7 +47,13 @@
|
||||
|
||||
那么只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。
|
||||
|
||||
本题是可以用回溯暴力搜索出所有答案的,但最后超时了,也不想再优化了,放弃回溯,直接上01背包吧。
|
||||
本题是可以用回溯暴力搜索出所有答案的,但最后超时了,也不想再优化了,放弃回溯。
|
||||
|
||||
是否有其他解法可以解决此题。
|
||||
|
||||
本题的本质是,能否把容量为 sum / 2的背包装满。
|
||||
|
||||
**这是 背包算法可以解决的经典类型题目**。
|
||||
|
||||
如果对01背包不够了解,建议仔细看完如下两篇:
|
||||
|
||||
@ -56,7 +62,7 @@
|
||||
|
||||
### 01背包问题
|
||||
|
||||
背包问题,大家都知道,有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
|
||||
01背包问题,大家都知道,有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
|
||||
|
||||
**背包问题有多种背包方式,常见的有:01背包、完全背包、多重背包、分组背包和混合背包等等。**
|
||||
|
||||
@ -64,32 +70,33 @@
|
||||
|
||||
**即一个商品如果可以重复多次放入是完全背包,而只能放入一次是01背包,写法还是不一样的。**
|
||||
|
||||
**要明确本题中我们要使用的是01背包,因为元素我们只能用一次。**
|
||||
**元素我们只能用一次,如果使用背包,那么也是01背包**
|
||||
|
||||
回归主题:首先,本题要求集合里能否出现总和为 sum / 2 的子集。
|
||||
|
||||
那么来一一对应一下本题,看看背包问题如何来解决。
|
||||
既有一个 只能装重量为 sum / 2 的背包,商品为数字,这些数字能不能把 这个背包装满。
|
||||
|
||||
**只有确定了如下四点,才能把01背包问题套到本题上来。**
|
||||
那每一件商品是数字的话,对应的重量 和 价值是多少呢?
|
||||
|
||||
* 背包的体积为sum / 2
|
||||
* 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
|
||||
* 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
|
||||
* 背包中每一个元素是不可重复放入。
|
||||
一个数字只有一个维度,即 重量等于价值。
|
||||
|
||||
以上分析完,我们就可以套用01背包,来解决这个问题了。
|
||||
当数字 可以装满 承载重量为 sum / 2 的背包的背包时,这个背包的价值也是 sum / 2。
|
||||
|
||||
那么这道题就是 装满 承载重量为 sum / 2 的背包,价值最大是多少?
|
||||
|
||||
如果最大价值是 sum / 2,说明正好被商品装满了。
|
||||
|
||||
因为商品是数字,重量和对应的价值是相同的。
|
||||
|
||||
以上分析完,我们就可以直接用01背包 来解决这个问题了。
|
||||
|
||||
动规五部曲分析如下:
|
||||
|
||||
1. 确定dp数组以及下标的含义
|
||||
|
||||
01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。
|
||||
01背包中,dp[j] 表示: 容量(所能装的重量)为j的背包,所背的物品价值最大可以为dp[j]。
|
||||
|
||||
本题中每一个元素的数值既是重量,也是价值。
|
||||
|
||||
**套到本题,dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]**。
|
||||
|
||||
那么如果背包容量为target, dp[target]就是装满 背包之后的重量,所以 当 dp[target] == target 的时候,背包就装满了。
|
||||
如果背包所载重量为target, dp[target]就是装满 背包之后的总价值,因为 本题中每一个元素的数值既是重量,也是价值,所以,当 dp[target] == target 的时候,背包就装满了。
|
||||
|
||||
有录友可能想,那还有装不满的时候?
|
||||
|
||||
@ -192,12 +199,11 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
这道题目就是一道01背包应用类的题目,需要我们拆解题目,然后套入01背包的场景。
|
||||
这道题目就是一道01背包经典应用类的题目,需要我们拆解题目,然后才能发现可以使用01背包。
|
||||
|
||||
01背包相对于本题,主要要理解,题目中物品是nums[i],重量是nums[i],价值也是nums[i],背包体积是sum/2。
|
||||
|
||||
看代码的话,就可以发现,基本就是按照01背包的写法来的。
|
||||
|
||||
做完本题后,需要大家清晰:背包问题,不仅可以求 背包能被的最大价值,还可以求这个背包是否可以装满。
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
@ -311,7 +311,7 @@ func min(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
- 按右边界排序
|
||||
```Javascript
|
||||
var eraseOverlapIntervals = function(intervals) {
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
## 算法公开课
|
||||
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点](https://www.bilibili.com/video/BV1tP41177us?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点](https://www.bilibili.com/video/BV1tP41177us?share_source=copy_web),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
## 思路
|
||||
|
||||
|
@ -110,7 +110,7 @@ public:
|
||||
```
|
||||
|
||||
* 时间复杂度:O(nlog n),因为有一个快排
|
||||
* 空间复杂度:O(1),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||
* 空间复杂度:O(n),有一个快排,最差情况(倒序)时,需要n次递归调用。因此确实需要O(n)的栈空间
|
||||
|
||||
可以看出代码并不复杂。
|
||||
|
||||
@ -180,19 +180,25 @@ class Solution:
|
||||
```python
|
||||
class Solution: # 不改变原数组
|
||||
def findMinArrowShots(self, points: List[List[int]]) -> int:
|
||||
if len(points) == 0:
|
||||
return 0
|
||||
|
||||
points.sort(key = lambda x: x[0])
|
||||
sl,sr = points[0][0],points[0][1]
|
||||
|
||||
# points已经按照第一个坐标正序排列,因此只需要设置一个变量,记录右侧坐标(阈值)
|
||||
# 考虑一个气球范围包含两个不相交气球的情况:气球1: [1, 10], 气球2: [2, 5], 气球3: [6, 10]
|
||||
curr_min_right = points[0][1]
|
||||
count = 1
|
||||
|
||||
for i in points:
|
||||
if i[0]>sr:
|
||||
if i[0] > curr_min_right:
|
||||
# 当气球左侧大于这个阈值,那么一定就需要在发射一只箭,并且将阈值更新为当前气球的右侧
|
||||
count += 1
|
||||
sl,sr = i[0],i[1]
|
||||
curr_min_right = i[1]
|
||||
else:
|
||||
sl = max(sl,i[0])
|
||||
sr = min(sr,i[1])
|
||||
# 否则的话,我们只需要求阈值和当前气球的右侧的较小值来更新阈值
|
||||
curr_min_right = min(curr_min_right, i[1])
|
||||
return count
|
||||
|
||||
|
||||
```
|
||||
### Go
|
||||
```go
|
||||
@ -220,7 +226,7 @@ func min(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var findMinArrowShots = function(points) {
|
||||
points.sort((a, b) => {
|
||||
|
@ -488,6 +488,44 @@ int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums
|
||||
}
|
||||
```
|
||||
|
||||
### Ruby:
|
||||
|
||||
```ruby
|
||||
# @param {Integer[]} nums1
|
||||
# @param {Integer[]} nums2
|
||||
# @param {Integer[]} nums3
|
||||
# @param {Integer[]} nums4
|
||||
# @return {Integer}
|
||||
# 新思路:和版主的思路基本相同,只是对后面两个数组的二重循环,用一个方法调用外加一重循环替代,简化了一点。
|
||||
# 简单的说,就是把四数和变成了两个两数和的统计(结果放到两个 hash 中),然后再来一次两数和为0.
|
||||
# 把四个数分成两组两个数,然后分别计算每组可能的和情况,分别存入 hash 中,key 是 和,value 是 数量;
|
||||
# 最后,得到的两个 hash 只需要遍历一次,符合和为零的 value 相乘并加总。
|
||||
def four_sum_count(nums1, nums2, nums3, nums4)
|
||||
num_to_count_1 = two_sum_mapping(nums1, nums2)
|
||||
num_to_count_2 = two_sum_mapping(nums3, nums4)
|
||||
|
||||
count_sum = 0
|
||||
|
||||
num_to_count_1.each do |num, count|
|
||||
count_sum += num_to_count_2[-num] * count # 反查另一个 hash,看有没有匹配的,没有的话,hash 默认值为 0,不影响加总;有匹配的,乘积就是可能的情况
|
||||
end
|
||||
|
||||
count_sum
|
||||
end
|
||||
|
||||
def two_sum_mapping(nums1, nums2)
|
||||
num_to_count = Hash.new(0)
|
||||
|
||||
nums1.each do |num1|
|
||||
nums2.each do |nums2|
|
||||
num_to_count[num1 + nums2] += 1 # 统计和为 num1 + nums2 的有几个
|
||||
end
|
||||
end
|
||||
|
||||
num_to_count
|
||||
end
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -278,7 +278,7 @@ pub fn find_content_children(mut children: Vec<i32>, mut cookies: Vec<i32>) -> i
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```js
|
||||
var findContentChildren = function (g, s) {
|
||||
|
@ -362,7 +362,7 @@ func max(a,b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```javascript
|
||||
const findMaxForm = (strs, m, n) => {
|
||||
const dp = Array.from(Array(m+1), () => Array(n+1).fill(0));
|
||||
|
@ -375,7 +375,7 @@ func dfs(nums []int, start int) {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
|
||||
|
@ -791,7 +791,7 @@ func abs(x int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```javascript
|
||||
const findTargetSumWays = (nums, target) => {
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
## 算法公开课
|
||||
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
## 思路
|
||||
|
@ -185,7 +185,7 @@ class Solution:
|
||||
|
||||
> 版本二:针对版本一的优化
|
||||
|
||||
```python3
|
||||
```python
|
||||
class Solution:
|
||||
def nextGreaterElements(self, nums: List[int]) -> List[int]:
|
||||
res = [-1] * len(nums)
|
||||
@ -213,6 +213,40 @@ class Solution:
|
||||
### Go:
|
||||
|
||||
```go
|
||||
// 版本一
|
||||
func nextGreaterElements(nums []int) []int {
|
||||
// 拼接一个新的nums
|
||||
numsNew := make([]int, len(nums) * 2)
|
||||
copy(numsNew, nums)
|
||||
copy(numsNew[len(nums):], nums)
|
||||
// 用新的nums大小来初始化result
|
||||
result := make([]int, len(numsNew))
|
||||
for i := range result {
|
||||
result[i] = -1
|
||||
}
|
||||
|
||||
// 开始单调栈
|
||||
st := []int{0}
|
||||
for i := 1; i < len(numsNew); i++ {
|
||||
if numsNew[i] < numsNew[st[len(st)-1]] {
|
||||
st = append(st, i)
|
||||
} else if numsNew[i] == numsNew[st[len(st)-1]] {
|
||||
st = append(st, i)
|
||||
} else {
|
||||
for len(st) > 0 && numsNew[i] > numsNew[st[len(st)-1]] {
|
||||
result[st[len(st)-1]] = numsNew[i]
|
||||
st = st[:len(st)-1]
|
||||
}
|
||||
st = append(st, i)
|
||||
}
|
||||
}
|
||||
result = result[:len(result)/2]
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// 版本二
|
||||
func nextGreaterElements(nums []int) []int {
|
||||
length := len(nums)
|
||||
result := make([]int,length)
|
||||
|
@ -292,7 +292,7 @@ func fib(n int) int {
|
||||
return c
|
||||
}
|
||||
```
|
||||
### Javascript
|
||||
### JavaScript
|
||||
解法一
|
||||
```Javascript
|
||||
var fib = function(n) {
|
||||
|
@ -224,7 +224,7 @@ func longestPalindromeSubseq(s string) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
const longestPalindromeSubseq = (s) => {
|
||||
|
@ -349,7 +349,7 @@ impl Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
const change = (amount, coins) => {
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
## 算法公开课
|
||||
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
|
||||
## 思路
|
||||
|
@ -282,7 +282,7 @@ class Solution:
|
||||
return ''.join(res)
|
||||
```
|
||||
|
||||
### Python3 (v2):
|
||||
#### Python3 (v2):
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
@ -297,6 +297,21 @@ class Solution:
|
||||
return s
|
||||
```
|
||||
|
||||
#### Python3 (v3):
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def reverseStr(self, s: str, k: int) -> str:
|
||||
i = 0
|
||||
chars = list(s)
|
||||
|
||||
while i < len(chars):
|
||||
chars[i:i + k] = chars[i:i + k][::-1] # 反转后,更改原值为反转后值
|
||||
i += k * 2
|
||||
|
||||
return ''.join(chars)
|
||||
```
|
||||
|
||||
### Go:
|
||||
|
||||
```go
|
||||
|
@ -290,6 +290,7 @@ func min(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
动态规划二
|
||||
|
||||
```go
|
||||
@ -318,7 +319,9 @@ func max(x, y int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
|
||||
### JavaScript:
|
||||
|
||||
|
||||
```javascript
|
||||
// 方法一
|
||||
|
@ -102,7 +102,7 @@ dp[i][j]可以初始化为true么? 当然不行,怎能刚开始就全都匹
|
||||
|
||||
4. 确定遍历顺序
|
||||
|
||||
遍历顺序可有有点讲究了。
|
||||
遍历顺序可就有点讲究了。
|
||||
|
||||
首先从递推公式中可以看出,情况三是根据dp[i + 1][j - 1]是否为true,在对dp[i][j]进行赋值true的。
|
||||
|
||||
@ -465,7 +465,7 @@ func countSubstrings(s string) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
> 动态规划
|
||||
```javascript
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
## 算法公开课
|
||||
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[你修剪的方式不对,我来给你纠正一下!| LeetCode:669. 修剪二叉搜索树](https://www.bilibili.com/video/BV17P41177ud?share_source=copy_web),相信结合视频在看本篇题解,更有助于大家对本题的理解**。
|
||||
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[你修剪的方式不对,我来给你纠正一下!| LeetCode:669. 修剪二叉搜索树](https://www.bilibili.com/video/BV17P41177ud?share_source=copy_web),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
|
||||
|
||||
## 思路
|
||||
|
||||
|
@ -359,7 +359,7 @@ impl Solution {
|
||||
```
|
||||
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
> 动态规划:
|
||||
```javascript
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
在[贪心算法:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html)中使用贪心策略不用关心具体什么时候买卖,只要收集每天的正利润,最后稳稳的就是最大利润了。
|
||||
|
||||
而本题有了手续费,就要关系什么时候买卖了,因为计算所获得利润,需要考虑买卖利润可能不足以手续费的情况。
|
||||
而本题有了手续费,就要关心什么时候买卖了,因为计算所获得利润,需要考虑买卖利润可能不足以扣减手续费的情况。
|
||||
|
||||
如果使用贪心策略,就是最低值买,最高值(如果算上手续费还盈利)就卖。
|
||||
|
||||
@ -122,7 +122,7 @@ public:
|
||||
* 时间复杂度:O(n)
|
||||
* 空间复杂度:O(n)
|
||||
|
||||
当然可以对空间经行优化,因为当前状态只是依赖前一个状态。
|
||||
当然可以对空间进行优化,因为当前状态只是依赖前一个状态。
|
||||
|
||||
C++ 代码如下:
|
||||
|
||||
@ -243,7 +243,7 @@ func maxProfit(prices []int, fee int) int {
|
||||
return res
|
||||
}
|
||||
```
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
// 贪心思路
|
||||
var maxProfit = function(prices, fee) {
|
||||
|
@ -46,7 +46,7 @@
|
||||
* 时间复杂度:O(n)
|
||||
* 空间复杂度:O(1)
|
||||
|
||||
本题使用贪心算法并不好理解,也很容易出错,那么我们再来看看是使用动规的方法如何解题。
|
||||
本题使用贪心算法并不好理解,也很容易出错,那么我们再来看看使用动规的方法如何解题。
|
||||
|
||||
相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
|
||||
这里重申一下dp数组的含义:
|
||||
|
||||
dp[i][0] 表示第i天持有股票所省最多现金。
|
||||
dp[i][0] 表示第i天持有股票所得最多现金。
|
||||
dp[i][1] 表示第i天不持有股票所得最多现金
|
||||
|
||||
|
||||
@ -226,7 +226,7 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```javascript
|
||||
const maxProfit = (prices,fee) => {
|
||||
|
@ -292,7 +292,7 @@ func monotoneIncreasingDigits(N int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var monotoneIncreasingDigits = function(n) {
|
||||
n = n.toString()
|
||||
|
@ -312,7 +312,7 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var partitionLabels = function(s) {
|
||||
let hash = {}
|
||||
|
@ -226,7 +226,7 @@ func lemonadeChange(bills []int) bool {
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var lemonadeChange = function(bills) {
|
||||
let fiveCount = 0
|
||||
|
@ -196,7 +196,22 @@ public class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Rust
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn valid_mountain_array(arr: Vec<i32>) -> bool {
|
||||
let mut i = 0;
|
||||
let mut j = arr.len() - 1;
|
||||
while i < arr.len() - 1 && arr[i] < arr[i + 1] {
|
||||
i += 1;
|
||||
}
|
||||
while j > 0 && arr[j] < arr[j - 1] {
|
||||
j -= 1;
|
||||
}
|
||||
i > 0 && j < arr.len() - 1 && i == j
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
@ -536,7 +536,7 @@ func min(a, b int) int {
|
||||
|
||||
```
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```Javascript
|
||||
var minCameraCover = function(root) {
|
||||
|
@ -301,7 +301,7 @@ impl Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
```Javascript
|
||||
/**
|
||||
@ -327,7 +327,7 @@ var sortedSquares = function(nums) {
|
||||
};
|
||||
```
|
||||
|
||||
### Typescript:
|
||||
### TypeScript:
|
||||
|
||||
双指针法:
|
||||
|
||||
|
@ -207,7 +207,7 @@ func largestSumAfterKNegations(nums []int, K int) int {
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```Javascript
|
||||
var largestSumAfterKNegations = function(nums, k) {
|
||||
|
||||
|
@ -8,11 +8,16 @@
|
||||
|
||||
[力扣题目链接](https://leetcode.cn/problems/uncrossed-lines/)
|
||||
|
||||
我们在两条独立的水平线上按给定的顺序写下 A 和 B 中的整数。
|
||||
在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。
|
||||
|
||||
现在,我们可以绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且我们绘制的直线不与任何其他连线(非水平线)相交。
|
||||
现在,可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,这些直线需要同时满足:
|
||||
|
||||
以这种方法绘制线条,并返回我们可以绘制的最大连线数。
|
||||
* nums1[i] == nums2[j]
|
||||
* 且绘制的直线不与任何其他连线(非水平线)相交。
|
||||
|
||||
请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。
|
||||
|
||||
以这种方法绘制线条,并返回可以绘制的最大连线数。
|
||||
|
||||
|
||||

|
||||
@ -26,16 +31,16 @@
|
||||
|
||||
相信不少录友看到这道题目都没啥思路,我们来逐步分析一下。
|
||||
|
||||
绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且直线不能相交!
|
||||
绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,只要 nums1[i] == nums2[j],且直线不能相交!
|
||||
|
||||
直线不能相交,这就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,链接相同数字的直线就不会相交。
|
||||
直线不能相交,这就是说明在字符串nums1中 找到一个与字符串nums2相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,连接相同数字的直线就不会相交。
|
||||
|
||||
拿示例一A = [1,4,2], B = [1,2,4]为例,相交情况如图:
|
||||
拿示例一nums1 = [1,4,2], nums2 = [1,2,4]为例,相交情况如图:
|
||||
|
||||
|
||||

|
||||
|
||||
其实也就是说A和B的最长公共子序列是[1,4],长度为2。 这个公共子序列指的是相对顺序不变(即数字4在字符串A中数字1的后面,那么数字4也应该在字符串B数字1的后面)
|
||||
其实也就是说nums1和nums2的最长公共子序列是[1,4],长度为2。 这个公共子序列指的是相对顺序不变(即数字4在字符串nums1中数字1的后面,那么数字4也应该在字符串nums2数字1的后面)
|
||||
|
||||
这么分析完之后,大家可以发现:**本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!**
|
||||
|
||||
@ -52,18 +57,18 @@
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int maxUncrossedLines(vector<int>& A, vector<int>& B) {
|
||||
vector<vector<int>> dp(A.size() + 1, vector<int>(B.size() + 1, 0));
|
||||
for (int i = 1; i <= A.size(); i++) {
|
||||
for (int j = 1; j <= B.size(); j++) {
|
||||
if (A[i - 1] == B[j - 1]) {
|
||||
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
|
||||
vector<vector<int>> dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 0));
|
||||
for (int i = 1; i <= nums1.size(); i++) {
|
||||
for (int j = 1; j <= nums2.size(); j++) {
|
||||
if (nums1[i - 1] == nums2[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[A.size()][B.size()];
|
||||
return dp[nums1.size()][nums2.size()];
|
||||
}
|
||||
};
|
||||
```
|
||||
@ -110,11 +115,11 @@ public:
|
||||
|
||||
```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]:
|
||||
def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int:
|
||||
dp = [[0] * (len(nums2)+1) for _ in range(len(nums1)+1)]
|
||||
for i in range(1, len(nums1)+1):
|
||||
for j in range(1, len(nums2)+1):
|
||||
if nums1[i-1] == nums2[j-1]:
|
||||
dp[i][j] = dp[i-1][j-1] + 1
|
||||
else:
|
||||
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
|
||||
@ -124,23 +129,22 @@ class Solution:
|
||||
### Go:
|
||||
|
||||
```go
|
||||
func maxUncrossedLines(A []int, B []int) int {
|
||||
m, n := len(A), len(B)
|
||||
dp := make([][]int, m+1)
|
||||
func maxUncrossedLines(nums1 []int, nums2 []int) int {
|
||||
dp := make([][]int, len(nums1) + 1)
|
||||
for i := range dp {
|
||||
dp[i] = make([]int, n+1)
|
||||
dp[i] = make([]int, len(nums2) + 1)
|
||||
}
|
||||
|
||||
for i := 1; i <= len(A); i++ {
|
||||
for j := 1; j <= len(B); j++ {
|
||||
if (A[i - 1] == B[j - 1]) {
|
||||
for i := 1; i <= len(nums1); i++ {
|
||||
for j := 1; j <= len(nums2); j++ {
|
||||
if (nums1[i - 1] == nums2[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[m][n]
|
||||
return dp[len(nums1)][len(nums2)]
|
||||
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ class Solution {
|
||||
int top = -1;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
// 当 top > 0,即栈中有字符时,当前字符如果和栈中字符相等,弹出栈顶字符,同时 top--
|
||||
// 当 top >= 0,即栈中有字符时,当前字符如果和栈中字符相等,弹出栈顶字符,同时 top--
|
||||
if (top >= 0 && res.charAt(top) == c) {
|
||||
res.deleteCharAt(top);
|
||||
top--;
|
||||
|
@ -80,7 +80,7 @@ if (text1[i - 1] == text2[j - 1]) {
|
||||
|
||||
先看看dp[i][0]应该是多少呢?
|
||||
|
||||
test1[0, i-1]和空串的最长公共子序列自然是0,所以dp[i][0] = 0;
|
||||
text1[0, i-1]和空串的最长公共子序列自然是0,所以dp[i][0] = 0;
|
||||
|
||||
同理dp[0][j]也是0。
|
||||
|
||||
|
@ -221,6 +221,28 @@ func uniqueOccurrences(arr []int) bool {
|
||||
}
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
```rust
|
||||
use std::collections::{HashMap, HashSet};
|
||||
impl Solution {
|
||||
pub fn unique_occurrences(arr: Vec<i32>) -> bool {
|
||||
let mut hash = HashMap::<i32, i32>::new();
|
||||
for x in arr {
|
||||
*hash.entry(x).or_insert(0) += 1;
|
||||
}
|
||||
let mut set = HashSet::<i32>::new();
|
||||
for (_k, v) in hash {
|
||||
if set.contains(&v) {
|
||||
return false
|
||||
} else {
|
||||
set.insert(v);
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -260,6 +260,22 @@ function smallerNumbersThanCurrent(nums: number[]): number[] {
|
||||
};
|
||||
```
|
||||
|
||||
### rust
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
impl Solution {
|
||||
pub fn smaller_numbers_than_current(nums: Vec<i32>) -> Vec<i32> {
|
||||
let mut v = nums.clone();
|
||||
v.sort();
|
||||
let mut hash = HashMap::new();
|
||||
for i in 0..v.len() {
|
||||
// rust中使用or_insert插入值, 如果存在就不插入,可以使用正序遍历
|
||||
hash.entry(v[i]).or_insert(i as i32);
|
||||
}
|
||||
nums.into_iter().map(|x| *hash.get(&x).unwrap()).collect()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
|
@ -213,7 +213,7 @@ class Solution:
|
||||
return find(source) == find(destination)
|
||||
```
|
||||
|
||||
### Javascript:
|
||||
### JavaScript:
|
||||
|
||||
Javascript 并查集解法如下:
|
||||
|
||||
|
@ -911,7 +911,7 @@ func main() {
|
||||
|
||||
### Rust
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
### TypeScript
|
||||
|
||||
|
@ -578,7 +578,7 @@ int main() {
|
||||
更新 minDist数组,即:源点(节点1) 到 节点2 和 节点3的距离。
|
||||
|
||||
* 源点到节点2的最短距离为100,小于原minDist[2]的数值max,更新minDist[2] = 100
|
||||
* 源点到节点3的最短距离为1,小于原minDist[3]的数值max,更新minDist[4] = 1
|
||||
* 源点到节点3的最短距离为1,小于原minDist[3]的数值max,更新minDist[3] = 1
|
||||
|
||||
-------------------
|
||||
|
||||
@ -867,7 +867,7 @@ if __name__ == "__main__":
|
||||
|
||||
### Rust
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```js
|
||||
function dijkstra(grid, start, end) {
|
||||
|
@ -547,7 +547,7 @@ if __name__ == "__main__":
|
||||
|
||||
### Rust
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```js
|
||||
function kruskal(v, edges) {
|
||||
|
@ -507,7 +507,7 @@ int main() {
|
||||
|
||||
所以我们求最小生成树的权值和就是计算后的minDist数组数值总和。
|
||||
|
||||
最后我们拓展了如何求职 最小生成树 的每一条边,其实 添加的代码很简单,主要是理解 为什么使用 parent数组 来记录边 以及 在哪里 更新parent数组。
|
||||
最后我们拓展了如何获得最小生成树的每一条边,其实添加的代码很简单,主要是理解为什么使用parent数组来记录边以及在哪里更新parent数组。
|
||||
|
||||
同时,因为使用一维数组,数组的下标和数组如何赋值很重要,不要搞反,导致结果被覆盖。
|
||||
|
||||
@ -692,7 +692,7 @@ if __name__ == "__main__":
|
||||
|
||||
### Rust
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
```js
|
||||
function prim(v, edges) {
|
||||
const grid = Array.from({ length: v + 1 }, () => new Array(v + 1).fill(10001)); // Fixed grid initialization
|
||||
|
@ -350,7 +350,29 @@ function reverseStr(s, start, end) {
|
||||
|
||||
|
||||
### Swift:
|
||||
```swift
|
||||
func rotateWords(_ s: String, _ k: Int) -> String {
|
||||
var chars = Array(s)
|
||||
// 先反转整体
|
||||
reverseWords(&chars, start: 0, end: s.count - 1)
|
||||
// 反转前半段
|
||||
reverseWords(&chars, start: 0, end: k - 1)
|
||||
// 反转后半段
|
||||
reverseWords(&chars, start: k, end: s.count - 1)
|
||||
return String(chars)
|
||||
}
|
||||
|
||||
// 反转start...end 的字符数组
|
||||
func reverseWords(_ chars: inout [Character], start: Int, end: Int) {
|
||||
var left = start
|
||||
var right = end
|
||||
while left < right, right < chars.count {
|
||||
(chars[left], chars[right]) = (chars[right], chars[left])
|
||||
left += 1
|
||||
right -= 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### PHP:
|
||||
|
@ -462,7 +462,7 @@ if __name__ == "__main__":
|
||||
|
||||
### Rust
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```js
|
||||
async function main() {
|
||||
|
@ -483,7 +483,7 @@ if __name__ == "__main__":
|
||||
|
||||
### Rust
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
```js
|
||||
async function main() {
|
||||
|
@ -54,7 +54,7 @@ circle
|
||||
|
||||
## 思路
|
||||
|
||||
本题是 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 延伸题目。
|
||||
本题是 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 延伸题目。
|
||||
|
||||
本题是要我们判断 负权回路,也就是图中出现环且环上的边总权值为负数。
|
||||
|
||||
@ -64,7 +64,7 @@ circle
|
||||
|
||||
接下来我们来看 如何使用 bellman_ford 算法来判断 负权回路。
|
||||
|
||||
在 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 中 我们讲了 bellman_ford 算法的核心就是一句话:对 所有边 进行 n-1 次松弛。 同时文中的 【拓展】部分, 我们也讲了 松弛n次以上 会怎么样?
|
||||
在 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 中 我们讲了 bellman_ford 算法的核心就是一句话:对 所有边 进行 n-1 次松弛。 同时文中的 【拓展】部分, 我们也讲了 松弛n次以上 会怎么样?
|
||||
|
||||
在没有负权回路的图中,松弛 n 次以上 ,结果不会有变化。
|
||||
|
||||
@ -72,7 +72,7 @@ circle
|
||||
|
||||
那么每松弛一次,都会更新最短路径,所以结果会一直有变化。
|
||||
|
||||
(如果对于 bellman_ford 不了解的录友,建议详细看这里:[kama94.城市间货物运输I](./kama94.城市间货物运输I.md))
|
||||
(如果对于 bellman_ford 不了解的录友,建议详细看这里:[kama94.城市间货物运输I](./0094.城市间货物运输I.md))
|
||||
|
||||
以上为理论分析,接下来我们再画图举例。
|
||||
|
||||
@ -94,13 +94,13 @@ circle
|
||||
|
||||
如果在负权回路多绕两圈,三圈,无穷圈,那么我们的总成本就会无限小, 如果要求最小成本的话,你会发现本题就无解了。
|
||||
|
||||
在 bellman_ford 算法中,松弛 n-1 次所有的边 就可以求得 起点到任何节点的最短路径,松弛 n 次以上,minDist数组(记录起到到其他节点的最短距离)中的结果也不会有改变 (如果对 bellman_ford 算法 不了解,也不知道 minDist 是什么,建议详看上篇讲解[kama94.城市间货物运输I](./kama94.城市间货物运输I.md))
|
||||
在 bellman_ford 算法中,松弛 n-1 次所有的边 就可以求得 起点到任何节点的最短路径,松弛 n 次以上,minDist数组(记录起到到其他节点的最短距离)中的结果也不会有改变 (如果对 bellman_ford 算法 不了解,也不知道 minDist 是什么,建议详看上篇讲解[kama94.城市间货物运输I](./0094.城市间货物运输I.md))
|
||||
|
||||
而本题有负权回路的情况下,一直都会有更短的最短路,所以 松弛 第n次,minDist数组 也会发生改变。
|
||||
|
||||
那么解决本题的 核心思路,就是在 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 的基础上,再多松弛一次,看minDist数组 是否发生变化。
|
||||
那么解决本题的 核心思路,就是在 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 的基础上,再多松弛一次,看minDist数组 是否发生变化。
|
||||
|
||||
代码和 [kama94.城市间货物运输I](./kama94.城市间货物运输I.md) 基本是一样的,如下:(关键地方已注释)
|
||||
代码和 [kama94.城市间货物运输I](./0094.城市间货物运输I.md) 基本是一样的,如下:(关键地方已注释)
|
||||
|
||||
```CPP
|
||||
#include <iostream>
|
||||
@ -392,7 +392,7 @@ if __name__ == "__main__":
|
||||
|
||||
### Rust
|
||||
|
||||
### Javascript
|
||||
### JavaScript
|
||||
|
||||
### TypeScript
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user