Merge branch 'master' into 583-minDistance

This commit is contained in:
程序员Carl
2024-12-02 09:47:45 +08:00
committed by GitHub
124 changed files with 1590 additions and 581 deletions

BIN
.DS_Store vendored

Binary file not shown.

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.idea/
.DS_Store
.vscode
.temp
.cache
*.iml
__pycache__

View File

@ -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)

View File

@ -341,7 +341,7 @@ impl Solution {
}
```
### Javascript:
### JavaScript:
```javascript
var twoSum = function (nums, target) {

View File

@ -275,7 +275,7 @@ def is_valid(strs)
end
```
### Javascript:
### JavaScript:
```javascript
var isValid = function (s) {

View File

@ -286,7 +286,7 @@ func swapPairs(head *ListNode) *ListNode {
}
```
### Javascript:
### JavaScript:
```javascript
var swapPairs = function (head) {

View File

@ -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) {

View File

@ -460,7 +460,7 @@ func isvalid(row, col int, k byte, board [][]byte) bool {
### Javascript
### JavaScript
```Javascript
var solveSudoku = function(board) {

View File

@ -374,7 +374,7 @@ func max(a, b int) int {
}
```
### Javascript
### JavaScript
```Javascript
var jump = function(nums) {

View File

@ -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>

View File

@ -283,7 +283,7 @@ func dfs(nums []int, cur int) {
}
```
### Javascript
### JavaScript
```javascript
var permuteUnique = function (nums) {

View File

@ -451,7 +451,7 @@ func isValid(n, row, col int, chessboard [][]string) bool {
```
### Javascript
### JavaScript
```Javascript
/**
* @param {number} n

View File

@ -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) {

View File

@ -260,7 +260,7 @@ class Solution {
}
```
### Javascript
### JavaScript
```
/**
* @param {number[][]} matrix

View File

@ -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) {

View File

@ -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]);

View File

@ -411,7 +411,7 @@ func uniquePaths(m int, n int) int {
}
```
### Javascript
### JavaScript
```Javascript
var uniquePaths = function(m, n) {

View File

@ -465,7 +465,7 @@ func uniquePathsWithObstacles(obstacleGrid [][]int) int {
}
```
### Javascript
### JavaScript
```Javascript
var uniquePathsWithObstacles = function(obstacleGrid) {

View File

@ -327,7 +327,7 @@ func climbStairs(n int) int {
return dp[n]
}
```
### Javascript
### JavaScript
```Javascript
var climbStairs = function(n) {
// dp[i] 为第 i 阶楼梯有多少种方法爬到楼顶

View File

@ -313,7 +313,7 @@ func Min(args ...int) int {
}
```
### Javascript
### JavaScript
```javascript
const minDistance = (word1, word2) => {

View File

@ -468,7 +468,7 @@ func dfs(n int, k int, start int) {
}
```
### Javascript
### JavaScript
未剪枝:
```js

View File

@ -246,7 +246,7 @@ func dfs(nums []int, start int) {
}
```
### Javascript
### JavaScript
```Javascript
var subsets = function(nums) {

View File

@ -376,7 +376,7 @@ func dfs(nums []int, start int) {
```
### Javascript
### JavaScript
```Javascript

View File

@ -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段了最后一段不需要再加点

View File

@ -221,7 +221,7 @@ func numTrees(n int)int{
}
```
### Javascript
### JavaScript
```Javascript
const numTrees =(n) => {

View File

@ -22,7 +22,7 @@
## 算法公开课
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[你对二叉搜索树了解的还不够! | LeetCode98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频看本篇题解,更有助于大家对本题的理解**。
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[你对二叉搜索树了解的还不够! | LeetCode98.验证二叉搜索树](https://www.bilibili.com/video/BV18P411n7Q4),相信结合视频看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -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) {

View File

@ -604,7 +604,7 @@ func maxDepth(root *Node) int {
}
```
### Javascript :
### JavaScript :
104.二叉树的最大深度

View File

@ -830,7 +830,7 @@ func traverse(node *TreeNode, result *[][]int, currPath *[]int, targetSum int) {
}
```
### Javascript
### JavaScript
0112.路径总和

View File

@ -265,7 +265,7 @@ func numDistinct(s string, t string) int {
}
```
### Javascript:
### JavaScript:
```javascript
const numDistinct = (s, t) => {

View File

@ -249,7 +249,7 @@ func max(a, b int) int {
}
```
### Javascript:
### JavaScript:
贪心

View File

@ -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

View File

@ -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:
> 版本一:

View File

@ -396,7 +396,7 @@ func canCompleteCircuit(gas []int, cost []int) int {
}
```
### Javascript
### JavaScript
暴力
```js
var canCompleteCircuit = function(gas, cost) {

View File

@ -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)

View File

@ -108,7 +108,7 @@ public:
}
}
int result = st.top();
long long result = st.top();
st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
return result;
}

View File

@ -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
版本一:

View File

@ -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:

View File

@ -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">

View File

@ -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"/>

View File

@ -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">

View File

@ -266,7 +266,7 @@ var minSubArrayLen = function(target, nums) {
};
```
### Typescript
### TypeScript
```typescript
function minSubArrayLen(target: number, nums: number[]): number {

View File

@ -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)

View File

@ -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),相信结合视频看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -36,7 +36,7 @@
## 算法公开课
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[自底向上查找,有点难度! | LeetCode236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频看本篇题解,更有助于大家对本题的理解**。
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[自底向上查找,有点难度! | LeetCode236. 二叉树的最近公共祖先](https://www.bilibili.com/video/BV1jd4y1B7E2),相信结合视频看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -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
/**

View File

@ -346,7 +346,7 @@ func min(a, b int) int {
}
```
### Javascript:
### JavaScript:
```Javascript
// 先遍历物品,再遍历背包

View File

@ -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;
}
}
}
}
```

View File

@ -248,7 +248,7 @@ func lengthOfLIS(nums []int ) int {
}
```
### Javascript:
### JavaScript:
```javascript
const lengthOfLIS = (nums) => {

View File

@ -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

View File

@ -427,7 +427,7 @@ impl Solution {
}
```
### Javascript
### JavaScript
```javascript
// 遍历物品

View File

@ -535,7 +535,7 @@ func findItinerary(tickets [][]string) []string {
}
```
### Javascript
### JavaScript
```Javascript

View File

@ -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}

View File

@ -385,7 +385,7 @@ func integerBreak(n int) int {
}
```
### Javascript
### JavaScript
```Javascript
var integerBreak = function(n) {
let dp = new Array(n + 1).fill(0)

View File

@ -466,7 +466,7 @@ func max(a, b int) int {
}
```
### Javascript
### JavaScript
**贪心**

View File

@ -254,7 +254,7 @@ func combinationSum4(nums []int, target int) int {
}
```
### Javascript
### JavaScript
```javascript
const combinationSum4 = (nums, target) => {

View File

@ -270,7 +270,7 @@ func reconstructQueue(people [][]int) [][]int {
}
```
### Javascript
### JavaScript
```Javascript
var reconstructQueue = function(people) {

View File

@ -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背包的写法来的
做完本题后,需要大家清晰:背包问题,不仅可以求 背包能被的最大价值,还可以求这个背包是否可以装满
## 其他语言版本

View File

@ -311,7 +311,7 @@ func min(a, b int) int {
}
```
### Javascript
### JavaScript
- 按右边界排序
```Javascript
var eraseOverlapIntervals = function(intervals) {

View File

@ -26,7 +26,7 @@
## 算法公开课
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[调整二叉树的结构最难!| LeetCode450.删除二叉搜索树中的节点](https://www.bilibili.com/video/BV1tP41177us?share_source=copy_web),相信结合视频看本篇题解,更有助于大家对本题的理解**。
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[调整二叉树的结构最难!| LeetCode450.删除二叉搜索树中的节点](https://www.bilibili.com/video/BV1tP41177us?share_source=copy_web),相信结合视频看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -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) => {

View File

@ -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"/>

View File

@ -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) {

View File

@ -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));

View File

@ -375,7 +375,7 @@ func dfs(nums []int, start int) {
}
```
### Javascript
### JavaScript
```Javascript

View File

@ -791,7 +791,7 @@ func abs(x int) int {
}
```
### Javascript
### JavaScript
```javascript
const findTargetSumWays = (nums, target) => {

View File

@ -35,7 +35,7 @@
## 算法公开课
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频看本篇题解,更有助于大家对本题的理解**。
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[不仅双指针,还有代码技巧可以惊艳到你! | LeetCode501.二叉搜索树中的众数](https://www.bilibili.com/video/BV1fD4y117gp),相信结合视频看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -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)

View File

@ -292,7 +292,7 @@ func fib(n int) int {
return c
}
```
### Javascript
### JavaScript
解法一
```Javascript
var fib = function(n) {

View File

@ -224,7 +224,7 @@ func longestPalindromeSubseq(s string) int {
}
```
### Javascript
### JavaScript
```javascript
const longestPalindromeSubseq = (s) => {

View File

@ -349,7 +349,7 @@ impl Solution {
}
```
### Javascript
### JavaScript
```javascript
const change = (amount, coins) => {

View File

@ -21,7 +21,7 @@
## 算法公开课
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频看本篇题解,更有助于大家对本题的理解**。
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[二叉搜索树中,需要掌握如何双指针遍历!| LeetCode530.二叉搜索树的最小绝对差](https://www.bilibili.com/video/BV1DD4y11779),相信结合视频看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -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

View File

@ -290,6 +290,7 @@ func min(a, b int) int {
}
```
动态规划二
```go
@ -318,7 +319,9 @@ func max(x, y int) int {
}
```
### Javascript
### JavaScript
```javascript
// 方法一

View File

@ -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

View File

@ -22,7 +22,7 @@
## 算法公开课
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[你修剪的方式不对,我来给你纠正一下!| LeetCode669. 修剪二叉搜索树](https://www.bilibili.com/video/BV17P41177ud?share_source=copy_web),相信结合视频看本篇题解,更有助于大家对本题的理解**。
**[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html)[你修剪的方式不对,我来给你纠正一下!| LeetCode669. 修剪二叉搜索树](https://www.bilibili.com/video/BV17P41177ud?share_source=copy_web),相信结合视频看本篇题解,更有助于大家对本题的理解**。
## 思路

View File

@ -359,7 +359,7 @@ impl Solution {
```
### Javascript
### JavaScript
> 动态规划:
```javascript

View File

@ -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) {

View File

@ -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) => {

View File

@ -292,7 +292,7 @@ func monotoneIncreasingDigits(N int) int {
}
```
### Javascript
### JavaScript
```Javascript
var monotoneIncreasingDigits = function(n) {
n = n.toString()

View File

@ -312,7 +312,7 @@ func max(a, b int) int {
}
```
### Javascript
### JavaScript
```Javascript
var partitionLabels = function(s) {
let hash = {}

View File

@ -226,7 +226,7 @@ func lemonadeChange(bills []int) bool {
}
```
### Javascript
### JavaScript
```Javascript
var lemonadeChange = function(bills) {
let fiveCount = 0

View File

@ -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">

View File

@ -536,7 +536,7 @@ func min(a, b int) int {
```
### Javascript
### JavaScript
```Javascript
var minCameraCover = function(root) {

View File

@ -301,7 +301,7 @@ impl Solution {
}
}
```
### Javascript
### JavaScript
```Javascript
/**
@ -327,7 +327,7 @@ var sortedSquares = function(nums) {
};
```
### Typescript
### TypeScript
双指针法:

View File

@ -207,7 +207,7 @@ func largestSumAfterKNegations(nums []int, K int) int {
```
### Javascript
### JavaScript
```Javascript
var largestSumAfterKNegations = function(nums, k) {

View File

@ -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]
* 且绘制的直线不与任何其他连线(非水平线)相交。
请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。
以这种方法绘制线条,并返回可以绘制的最大连线数。
![1035.不相交的线](https://code-thinking-1253855093.file.myqcloud.com/pics/2021032116363533.png)
@ -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]为例,相交情况如图:
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210914145158.png)
其实也就是说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)]
}

View File

@ -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--;

View File

@ -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。

View File

@ -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
}
}
```

View File

@ -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">

View File

@ -213,7 +213,7 @@ class Solution:
return find(source) == find(destination)
```
### Javascript
### JavaScript
Javascript 并查集解法如下:

View File

@ -911,7 +911,7 @@ func main() {
### Rust
### Javascript
### JavaScript
### TypeScript

View File

@ -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) {

View File

@ -547,7 +547,7 @@ if __name__ == "__main__":
### Rust
### Javascript
### JavaScript
```js
function kruskal(v, edges) {

View File

@ -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

View File

@ -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

View File

@ -462,7 +462,7 @@ if __name__ == "__main__":
### Rust
### Javascript
### JavaScript
```js
async function main() {

View File

@ -483,7 +483,7 @@ if __name__ == "__main__":
### Rust
### Javascript
### JavaScript
```js
async function main() {

View File

@ -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