diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md index 9854ccdc..ef485a39 100644 --- a/problems/0017.电话号码的字母组合.md +++ b/problems/0017.电话号码的字母组合.md @@ -409,6 +409,66 @@ var letterCombinations = function(digits) { }; ``` +C: +```c +char* path; +int pathTop; +char** result; +int resultTop; +char* letterMap[10] = {"", //0 + "", //1 + "abc", //2 + "def", //3 + "ghi", //4 + "jkl", //5 + "mno", //6 + "pqrs", //7 + "tuv", //8 + "wxyz", //9 +}; +void backTracking(char* digits, int index) { + //若当前下标等于digits数组长度 + if(index == strlen(digits)) { + //复制digits数组,因为最后要多存储一个0,所以数组长度要+1 + char* tempString = (char*)malloc(sizeof(char) * strlen(digits) + 1); + int j; + for(j = 0; j < strlen(digits); j++) { + tempString[j] = path[j]; + } + //char数组最后要以0结尾 + tempString[strlen(digits)] = 0; + result[resultTop++] = tempString; + return ; + } + //将字符数字转换为真的数字 + int digit = digits[index] - '0'; + //找到letterMap中对应的字符串 + char* letters = letterMap[digit]; + int i; + for(i = 0; i < strlen(letters); i++) { + path[pathTop++] = letters[i]; + //递归,处理下一层数字 + backTracking(digits, index+1); + pathTop--; + } +} + +char ** letterCombinations(char * digits, int* returnSize){ + //初始化path和result + path = (char*)malloc(sizeof(char) * strlen(digits)); + result = (char**)malloc(sizeof(char*) * 300); + + *returnSize = 0; + //若digits数组中元素个数为0,返回空集 + if(strlen(digits) == 0) + return result; + pathTop = resultTop = 0; + backTracking(digits, 0); + *returnSize = resultTop; + + return result; +} +``` ----------------------- diff --git a/problems/0037.解数独.md b/problems/0037.解数独.md index c946e838..94c5c198 100644 --- a/problems/0037.解数独.md +++ b/problems/0037.解数独.md @@ -376,6 +376,61 @@ class Solution: Go: +```go +func solveSudoku(board [][]byte) { + var backtracking func(board [][]byte) bool + backtracking=func(board [][]byte) bool{ + for i:=0;i<9;i++{ + for j:=0;j<9;j++{ + //判断此位置是否适合填数字 + if board[i][j]!='.'{ + continue + } + //尝试填1-9 + for k:='1';k<='9';k++{ + if isvalid(i,j,byte(k),board)==true{//如果满足要求就填 + board[i][j]=byte(k) + if backtracking(board)==true{ + return true + } + board[i][j]='.' + } + } + return false + } + } + return true + } + backtracking(board) +} +//判断填入数字是否满足要求 +func isvalid(row,col int,k byte,board [][]byte)bool{ + for i:=0;i<9;i++{//行 + if board[row][i]==k{ + return false + } + } + for i:=0;i<9;i++{//列 + if board[i][col]==k{ + return false + } + } + //方格 + startrow:=(row/3)*3 + startcol:=(col/3)*3 + for i:=startrow;i=target就应该终止遍历 + if(sum >= target) { + //若sum等于target,将当前的组合放入ans数组中 + if(sum == target) { + int* tempPath = (int*)malloc(sizeof(int) * pathTop); + int j; + for(j = 0; j < pathTop; j++) { + tempPath[j] = path[j]; + } + ans[ansTop] = tempPath; + length[ansTop++] = pathTop; + } + return ; + } + + int i; + for(i = index; i < candidatesSize; i++) { + //将当前数字大小加入sum + sum+=candidates[i]; + path[pathTop++] = candidates[i]; + backTracking(target, i, candidates, candidatesSize, sum); + sum-=candidates[i]; + pathTop--; + } +} + +int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){ + //初始化变量 + path = (int*)malloc(sizeof(int) * 50); + ans = (int**)malloc(sizeof(int*) * 200); + length = (int*)malloc(sizeof(int) * 200); + ansTop = pathTop = 0; + backTracking(target, 0, candidates, candidatesSize, 0); + + //设置返回的数组大小 + *returnSize = ansTop; + *returnColumnSizes = (int*)malloc(sizeof(int) * ansTop); + int i; + for(i = 0; i < ansTop; i++) { + (*returnColumnSizes)[i] = length[i]; + } + return ans; +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 4aab1782..8925ef81 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -392,7 +392,66 @@ var combinationSum2 = function(candidates, target) { } }; ``` +C: +```c +int* path; +int pathTop; +int** ans; +int ansTop; +//记录ans中每一个一维数组的大小 +int* length; +int cmp(const void* a1, const void* a2) { + return *((int*)a1) - *((int*)a2); +} +void backTracking(int* candidates, int candidatesSize, int target, int sum, int startIndex) { + if(sum >= target) { + //若sum等于target,复制当前path进入 + if(sum == target) { + int* tempPath = (int*)malloc(sizeof(int) * pathTop); + int j; + for(j = 0; j < pathTop; j++) { + tempPath[j] = path[j]; + } + length[ansTop] = pathTop; + ans[ansTop++] = tempPath; + } + return ; + } + + int i; + for(i = startIndex; i < candidatesSize; i++) { + //对同一层树中使用过的元素跳过 + if(i > startIndex && candidates[i] == candidates[i-1]) + continue; + path[pathTop++] = candidates[i]; + sum += candidates[i]; + backTracking(candidates, candidatesSize, target, sum, i + 1); + //回溯 + sum -= candidates[i]; + pathTop--; + } +} + +int** combinationSum2(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){ + path = (int*)malloc(sizeof(int) * 50); + ans = (int**)malloc(sizeof(int*) * 100); + length = (int*)malloc(sizeof(int) * 100); + pathTop = ansTop = 0; + //快速排序candidates,让相同元素挨到一起 + qsort(candidates, candidatesSize, sizeof(int), cmp); + + backTracking(candidates, candidatesSize, target, 0, 0); + + *returnSize = ansTop; + *returnColumnSizes = (int*)malloc(sizeof(int) * ansTop); + int i; + for(i = 0; i < ansTop; i++) { + (*returnColumnSizes)[i] = length[i]; + } + return ans; +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0042.接雨水.md b/problems/0042.接雨水.md index 4383a0b8..83b3f82c 100644 --- a/problems/0042.接雨水.md +++ b/problems/0042.接雨水.md @@ -134,6 +134,43 @@ public: 因为每次遍历列的时候,还要向两边寻找最高的列,所以时间复杂度为O(n^2)。 空间复杂度为O(1)。 + + +一种更简便的双指针方法: + +之前的双指针方法的原理是固定“底”的位置,往两边找比它高的“壁”,循环若干次求和。 + +我们逆向思维,把“壁”用两个初始位置在数组首末位置的指针表示,“壁”往中间推,同样可以让每个“底”都能找到最高的“壁” + +本质上就是改变了运算方向,从而减少了重复运算 + +代码如下: + +```C +int trap(int* height, int heightSize) { + int ans = 0; + int left = 0, right = heightSize - 1; //初始化两个指针到左右两边 + int leftMax = 0, rightMax = 0; //这两个值用来记录左右的“壁”的最高值 + while (left < right) { //两个指针重合就结束 + leftMax = fmax(leftMax, height[left]); + rightMax = fmax(rightMax, height[right]); + if (leftMax < rightMax) { + ans += leftMax - height[left]; //这里考虑的是下标为left的“底”能装多少水 + ++left;//指针的移动次序是这个方法的关键 + //这里左指针右移是因为左“墙”较矮,左边这一片实际情况下的盛水量是受制于这个矮的左“墙”的 + //而较高的右边在实际情况下的限制条件可能不是当前的左“墙”,比如限制条件可能是右“墙”,就能装更高的水, + } + else { + ans += rightMax - height[right]; //同理,考虑下标为right的元素 + --right; + } + } + return ans; +} +``` +时间复杂度 O(n) +空间复杂度 O(1) + ## 动态规划解法 在上一节的双指针解法中,我们可以看到只要记录左边柱子的最高高度 和 右边柱子的最高高度,就可以计算当前位置的雨水面积,这就是通过列来计算。 diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md index fbac50ac..9a7dc850 100644 --- a/problems/0059.螺旋矩阵II.md +++ b/problems/0059.螺旋矩阵II.md @@ -469,6 +469,65 @@ class Solution { } ``` +C: +```c +int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){ + //初始化返回的结果数组的大小 + *returnSize = n; + *returnColumnSizes = (int*)malloc(sizeof(int) * n); + //初始化返回结果数组ans + int** ans = (int**)malloc(sizeof(int*) * n); + int i; + for(i = 0; i < n; i++) { + ans[i] = (int*)malloc(sizeof(int) * n); + (*returnColumnSizes)[i] = n; + } + + //设置每次循环的起始位置 + int startX = 0; + int startY = 0; + //设置二维数组的中间值,若n为奇数。需要最后在中间填入数字 + int mid = n / 2; + //循环圈数 + int loop = n / 2; + //偏移数 + int offset = 1; + //当前要添加的元素 + int count = 1; + + while(loop) { + int i = startX; + int j = startY; + //模拟上侧从左到右 + for(; j < startY + n - offset; j++) { + ans[startX][j] = count++; + } + //模拟右侧从上到下 + for(; i < startX + n - offset; i++) { + ans[i][j] = count++; + } + //模拟下侧从右到左 + for(; j > startY; j--) { + ans[i][j] = count++; + } + //模拟左侧从下到上 + for(; i > startX; i--) { + ans[i][j] = count++; + } + //偏移值每次加2 + offset+=2; + //遍历起始位置每次+1 + startX++; + startY++; + loop--; + } + //若n为奇数需要单独给矩阵中间赋值 + if(n%2) + ans[mid][mid] = count; + + return ans; +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index 4b0908fd..5128d6ec 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -1173,7 +1173,7 @@ public: if (root != NULL) que.push(root); while (!que.empty()) { int size = que.size(); - vector vec; + // vector vec; Node* nodePre; Node* node; for (int i = 0; i < size; i++) { @@ -1570,9 +1570,43 @@ class Solution: return len(result) ``` - Go: +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func maxDepth(root *TreeNode) int { + ans:=0 + if root==nil{ + return 0 + } + queue:=list.New() + queue.PushBack(root) + for queue.Len()>0{ + length:=queue.Len() + for i:=0;i0{ + length:=queue.Len() + for i:=0;i { let dp = Array.from(Array(prices.length), () => Array(2).fill(0)); // dp[i][0] 表示第i天持有股票所得现金。 @@ -222,6 +223,21 @@ const maxProfit = (prices) => { return dp[prices.length -1][0]; }; + +// 方法二:动态规划(滚动数组) +const maxProfit = (prices) => { + // 滚动数组 + // have: 第i天持有股票最大收益; notHave: 第i天不持有股票最大收益 + let n = prices.length, + have = -prices[0], + notHave = 0; + for (let i = 1; i < n; i++) { + have = Math.max(have, notHave - prices[i]); + notHave = Math.max(notHave, have + prices[i]); + } + // 最终手里不持有股票才能保证收益最大化 + return notHave; +} ``` diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md index 9aa88fce..526efb14 100644 --- a/problems/0134.加油站.md +++ b/problems/0134.加油站.md @@ -281,6 +281,48 @@ func canCompleteCircuit(gas []int, cost []int) int { ``` Javascript: +暴力: +```js +var canCompleteCircuit = function(gas, cost) { + for(let i = 0; i < cost.length; i++) { + let rest = gas[i] - cost[i] //记录剩余油量 + // 以i为起点行驶一圈,index为下一个目的地 + let index = (i + 1) % cost.length + while(rest > 0 && index !== i) { + rest += gas[index] - cost[index] + index = (index + 1) % cost.length + } + if(rest >= 0 && index === i) return i + } + return -1 +}; +``` +解法一: +```js +var canCompleteCircuit = function(gas, cost) { + let curSum = 0 + let min = Infinity + for(let i = 0; i < gas.length; i++) { + let rest = gas[i] - cost[i] + curSum += rest + if(curSum < min) { + min = curSum + } + } + if(curSum < 0) return -1 //1.总油量 小于 总消耗量 + if(min >= 0) return 0 //2. 说明油箱里油没断过 + //3. 从后向前,看哪个节点能这个负数填平,能把这个负数填平的节点就是出发节点 + for(let i = gas.length -1; i >= 0; i--) { + let rest = gas[i] - cost[i] + min += rest + if(min >= 0) { + return i + } + } + return -1 +} +``` +解法二: ```Javascript var canCompleteCircuit = function(gas, cost) { const gasLen = gas.length diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index f75105f0..d7ab6cf7 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -392,7 +392,63 @@ var combinationSum3 = function(k, n) { }; ``` +C: +```c +int* path; +int pathTop; +int** ans; +int ansTop; +int getPathSum() { + int i; + int sum = 0; + for(i = 0; i < pathTop; i++) { + sum += path[i]; + } + return sum; +} +void backtracking(int targetSum, int k, int sum, int startIndex) { + if(pathTop == k) { + if(sum == targetSum) { + int* tempPath = (int*)malloc(sizeof(int) * k); + int j; + for(j = 0; j < k; j++) + tempPath[j] = path[j]; + ans[ansTop++] = tempPath; + } + // 如果path.size() == k 但sum != targetSum 直接返回 + return; + } + int i; + //从startIndex开始遍历,一直遍历到9 + for (i = startIndex; i <= 9; i++) { + sum += i; // 处理 + path[pathTop++] = i; // 处理 + backtracking(targetSum, k, sum, i + 1); // 注意i+1调整startIndex + sum -= i; // 回溯 + pathTop--;; // 回溯 + } +} + +int** combinationSum3(int k, int n, int* returnSize, int** returnColumnSizes){ + //初始化辅助变量 + path = (int*)malloc(sizeof(int) * k); + ans = (int**)malloc(sizeof(int*) * 20); + pathTop = ansTop = 0; + + backtracking(n, k, 0, 1); + + //设置返回的二维数组中元素个数为ansTop + *returnSize = ansTop; + //设置二维数组中每个元素个数的大小为k + *returnColumnSizes = (int*)malloc(sizeof(int) * ansTop); + int i; + for(i = 0; i < ansTop; i++) { + (*returnColumnSizes)[i] = k; + } + return ans; +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index b69cad55..fb5d831a 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -363,7 +363,9 @@ class Solution: return root ``` -### Go +### Go + +递归版本的前序遍历 ```Go func invertTree(root *TreeNode) *TreeNode { @@ -381,6 +383,96 @@ func invertTree(root *TreeNode) *TreeNode { } ``` +递归版本的后序遍历 + +```go +func invertTree(root *TreeNode) *TreeNode { + if root==nil{ + return root + } + invertTree(root.Left)//遍历左节点 + invertTree(root.Right)//遍历右节点 + root.Left,root.Right=root.Right,root.Left//交换 + return root +} +``` + +迭代版本的前序遍历 + +```go +func invertTree(root *TreeNode) *TreeNode { + stack:=[]*TreeNode{} + node:=root + for node!=nil||len(stack)>0{ + for node!=nil{ + node.Left,node.Right=node.Right,node.Left//交换 + stack=append(stack,node) + node=node.Left + } + node=stack[len(stack)-1] + stack=stack[:len(stack)-1] + node=node.Right + } + return root +} +``` + +迭代版本的后序遍历 + +```go +func invertTree(root *TreeNode) *TreeNode { + stack:=[]*TreeNode{} + node:=root + var prev *TreeNode + for node!=nil||len(stack)>0{ + for node!=nil{ + stack=append(stack,node) + node=node.Left + } + node=stack[len(stack)-1] + stack=stack[:len(stack)-1] + if node.Right==nil||node.Right==prev{ + node.Left,node.Right=node.Right,node.Left//交换 + prev=node + node=nil + }else { + stack=append(stack,node) + node=node.Right + } + } + return root +} +``` + +层序遍历 + +```go +func invertTree(root *TreeNode) *TreeNode { + if root==nil{ + return root + } + queue:=list.New() + node:=root + queue.PushBack(node) + for queue.Len()>0{ + length:=queue.Len() + for i:=0;i bool { + let mut record = vec![0; 26]; + + let baseChar = 'a'; + + for byte in s.bytes() { + record[byte as usize - baseChar as usize] += 1; + } + for byte in t.bytes() { + record[byte as usize - baseChar as usize] -= 1; + } + + record.iter().filter(|x| **x != 0).count() == 0 + } +} +``` ## 相关题目 * 383.赎金信 diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 6386c48d..e8a98527 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -408,25 +408,57 @@ class Solution { Python: ```Python class Solution: + """二叉树的所有路径 递归法""" + def binaryTreePaths(self, root: TreeNode) -> List[str]: - path=[] - res=[] - def backtrace(root, path): - if not root:return - path.append(root.val) - if (not root.left)and (not root.right): - res.append(path[:]) - ways=[] - if root.left:ways.append(root.left) - if root.right:ways.append(root.right) - for way in ways: - backtrace(way,path) - path.pop() - backtrace(root,path) - return ["->".join(list(map(str,i))) for i in res] + path, result = '', [] + self.traversal(root, path, result) + return result + + def traversal(self, cur: TreeNode, path: List, result: List): + path += str(cur.val) + # 如果当前节点为叶子节点,添加路径到结果中 + if not (cur.left or cur.right): + result.append(path) + return + + if cur.left: + self.traversal(cur.left, path + '->', result) + + if cur.right: + self.traversal(cur.right, path + '->', result) ``` +```python +from collections import deque + + +class Solution: + """二叉树的所有路径 迭代法""" + + def binaryTreePaths(self, root: TreeNode) -> List[str]: + # 题目中节点数至少为1 + stack, path_st, result = deque([root]), deque(), [] + path_st.append(str(root.val)) + + while stack: + cur = stack.pop() + path = path_st.pop() + # 如果当前节点为叶子节点,添加路径到结果中 + if not (cur.left or cur.right): + result.append(path) + if cur.right: + stack.append(cur.right) + path_st.append(path + '->' + str(cur.right.val)) + if cur.left: + stack.append(cur.left) + path_st.append(path + '->' + str(cur.left.val)) + + return result +``` + + Go: ```go func binaryTreePaths(root *TreeNode) []string { diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md index a5f18d58..a02c27d5 100644 --- a/problems/0344.反转字符串.md +++ b/problems/0344.反转字符串.md @@ -206,6 +206,7 @@ var reverseString = function(s) { Swift: ```swift +// 双指针 - 元组 func reverseString(_ s: inout [Character]) { var l = 0 var r = s.count - 1 @@ -216,11 +217,18 @@ func reverseString(_ s: inout [Character]) { r -= 1 } } + +// 双指针法 - 库函数 +func reverseString(_ s: inout [Character]) { + var j = s.count - 1 + for i in 0 ..< Int(Double(s.count) * 0.5) { + s.swapAt(i, j) + j -= 1 + } +} ``` - - ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index 0cbdf85f..28867092 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -238,6 +238,25 @@ class Solution { } ``` +Rust: +```rust +use std::collections::HashSet; +impl Solution { + pub fn intersection(nums1: Vec, nums2: Vec) -> Vec { + let mut resultSet: HashSet = HashSet::with_capacity(1000); + let nums1Set: HashSet = nums1.into_iter().collect(); + + for num in nums2.iter() { + if nums1Set.contains(num) { + resultSet.insert(*num); + } + } + + let ret: Vec = resultSet.into_iter().collect(); + ret + } +} +``` ## 相关题目 * 350.两个数组的交集 II diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index d1594015..75b31698 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -315,6 +315,28 @@ func canConstruct(_ ransomNote: String, _ magazine: String) -> Bool { } ``` +Rust: +```rust +impl Solution { + pub fn can_construct(ransom_note: String, magazine: String) -> bool { + let baseChar = 'a'; + let mut record = vec![0; 26]; + + for byte in magazine.bytes() { + record[byte as usize - baseChar as usize] += 1; + } + + for byte in ransom_note.bytes() { + record[byte as usize - baseChar as usize] -= 1; + if record[byte as usize - baseChar as usize] < 0 { + return false; + } + } + + return true; + } +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index 599a3180..415ff88b 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -227,6 +227,45 @@ class Solution: ``` Go: +``` +func canPartition(nums []int) bool { + /** + 动态五部曲: + 1.确定dp数组和下标含义 + 2.确定递推公式 + 3.dp数组初始化 + 4.dp遍历顺序 + 5.打印 + **/ + //确定和 + var sum int + for _,v:=range nums{ + sum+=v + } + if sum%2!=0{ //如果和为奇数,则不可能分成两个相等的数组 + return false + } + sum/=2 + //确定dp数组和下标含义 + var dp [][]bool //dp[i][j] 表示: 前i个石头是否总和不大于J + //初始化数组 + dp=make([][]bool,len(nums)+1) + for i,_:=range dp{ + dp[i]=make([]bool,sum+1) + dp[i][0]=true + } + for i:=1;i<=len(nums);i++{ + for j:=1;j<=sum;j++{//j是固定总量 + if j>=nums[i-1]{//如果容量够用则可放入背包 + dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i-1]] + }else{//如果容量不够用则不拿,维持前一个状态 + dp[i][j]=dp[i-1][j] + } + } + } + return dp[len(nums)][sum] +} +``` javaScript: diff --git a/problems/0435.无重叠区间.md b/problems/0435.无重叠区间.md index ae037f17..4e850114 100644 --- a/problems/0435.无重叠区间.md +++ b/problems/0435.无重叠区间.md @@ -274,6 +274,7 @@ func min(a,b int)int{ } ``` Javascript: +- 按右边界排序 ```Javascript var eraseOverlapIntervals = function(intervals) { intervals.sort((a, b) => { @@ -285,7 +286,7 @@ var eraseOverlapIntervals = function(intervals) { for(let i = 1; i < intervals.length; i++) { let interval = intervals[i] - if(interval[0] >= right) { + if(interval[0] >= end) { end = interval[1] count += 1 } @@ -294,6 +295,24 @@ var eraseOverlapIntervals = function(intervals) { return intervals.length - count }; ``` +- 按左边界排序 +```js +var eraseOverlapIntervals = function(intervals) { + // 按照左边界升序排列 + intervals.sort((a, b) => a[0] - b[0]) + let count = 1 + let end = intervals[intervals.length - 1][0] + // 倒序遍历,对单个区间来说,左边界越大越好,因为给前面区间的空间越大 + for(let i = intervals.length - 2; i >= 0; i--) { + if(intervals[i][1] <= end) { + count++ + end = intervals[i][0] + } + } + // count 记录的是最大非重复区间的个数 + return intervals.length - count +} +``` ----------------------- diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index a82c617b..475f93a0 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -282,6 +282,31 @@ func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int] } ``` +Rust: +```rust +use std::collections::HashMap; +impl Solution { + pub fn four_sum_count(nums1: Vec, nums2: Vec, nums3: Vec, nums4: Vec) -> i32 { + let mut umap:HashMap = HashMap::new(); + for num1 in &nums1 { + for num2 in &nums2 { + *umap.entry(num1 + num2).or_insert(0) += 1; + } + } + + let mut count = 0; + + for num3 in &nums3 { + for num4 in &nums4 { + let target:i32 = - (num3 + num4); + count += umap.get(&target).unwrap_or(&0); + } + } + + count + } +} +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/0463.岛屿的周长.md b/problems/0463.岛屿的周长.md index 18654758..609c25a5 100644 --- a/problems/0463.岛屿的周长.md +++ b/problems/0463.岛屿的周长.md @@ -84,6 +84,37 @@ public: Java: +```java +// 解法一 +class Solution { + // 上下左右 4 个方向 + int[] dirx = {-1, 1, 0, 0}; + int[] diry = {0, 0, -1, 1}; + + public int islandPerimeter(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + int res = 0; // 岛屿周长 + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 1) { + for (int k = 0; k < 4; k++) { + int x = i + dirx[k]; + int y = j + diry[k]; + // 当前位置是陆地,并且从当前位置4个方向扩展的“新位置”是“水域”或“新位置“越界,则会为周长贡献一条边 + if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == 0) { + res++; + continue; + } + } + } + } + } + return res; + } +} +``` + Python: Go: diff --git a/problems/0474.一和零.md b/problems/0474.一和零.md index e3b05704..5544c3c9 100644 --- a/problems/0474.一和零.md +++ b/problems/0474.一和零.md @@ -248,6 +248,53 @@ func max(a,b int) int { return b } ``` +> 传统背包,三维数组法 +```golang +func findMaxForm(strs []string, m int, n int) int { + //dp的第一个index代表项目的多少,第二个代表的是背包的容量 + //所以本处项目的多少是len(strs),容量为m和n + dp:=make([][][]int,len(strs)+1) + for i:=0;i<=len(strs);i++{ + //初始化背包容量 + strDp:=make([][]int,m+1) + for j:=0;j=zero&&j>=one{ + dp[k][i][j]=getMax(dp[k-1][i][j],dp[k-1][i-zero][j-one]+1) + } + } + } + } + return dp[len(strs)][m][n] +} +func getMax(a,b int)int{ + if a>b{ + return a + } + return b +} +``` Javascript: ```javascript diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index 4993bede..87fc579d 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -314,6 +314,47 @@ func findTargetSumWays(nums []int, target int) int { return dp[bag] } ``` +> 更新版,上一个跑不通了,因为会存在bag 小于0的情况 + +```go +func findTargetSumWays(nums []int, target int) int { + //先转化为数学问题 + //a-b=target + //a+b=sum + //a=(target+sum)/2 + //求出sum + var sum int + for _,value:=range nums{ + sum+=value + } + //如果sum { const sum = nums.reduce((a, b) => a+b); - if(target > sum) { + if(Math.abs(target) > sum) { return 0; } diff --git a/problems/0496.下一个更大元素I.md b/problems/0496.下一个更大元素I.md index 95aca60b..0c4fdd65 100644 --- a/problems/0496.下一个更大元素I.md +++ b/problems/0496.下一个更大元素I.md @@ -238,4 +238,37 @@ class Solution: return result ``` +Go: +```go +func nextGreaterElement(nums1 []int, nums2 []int) []int { + res := make([]int, len(nums1)) + for i:= range res { + res[i] = -1 + } + mp := map[int]int{} + for i,v := range nums1 { + mp[v] = i + } + // 单调栈 + stack := []int{} + stack = append(stack,0) + + for i:=1; i0 && nums2[i] > nums2[stack[len(stack)-1]] { + + top := stack[len(stack)-1] + + if _, ok := mp[nums2[top]]; ok { // 看map里是否存在这个元素 + index := mp[nums2[top]]; // 根据map找到nums2[top] 在 nums1中的下表 + res[index] = nums2[i] + } + + stack = stack[:len(stack)-1] // 出栈 + } + stack = append(stack, i) + } + return res +} +``` +
diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index 0dcbbb76..d2c05fd8 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -9,7 +9,7 @@ # 513.找树左下角的值 -[力扣题目链接]([https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/v)) +[力扣题目链接](https://leetcode-cn.com/problems/find-bottom-left-tree-value/) 给定一个二叉树,在树的最后一行找到最左边的值。 diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md index 1a6d39af..b644a0a3 100644 --- a/problems/0654.最大二叉树.md +++ b/problems/0654.最大二叉树.md @@ -258,16 +258,30 @@ class Solution { ## Python ```python -//递归法 class Solution: + """最大二叉树 递归法""" + def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode: - if not nums: return None //终止条件 - root = TreeNode(max(nums)) //新建节点 - p = nums.index(root.val) //找到最大值位置 - if p > 0: //保证有左子树 - root.left = self.constructMaximumBinaryTree(nums[:p]) //递归 - if p < len(nums): //保证有右子树 - root.right = self.constructMaximumBinaryTree(nums[p+1:]) //递归 + return self.traversal(nums, 0, len(nums)) + + def traversal(self, nums: List[int], begin: int, end: int) -> TreeNode: + # 列表长度为0时返回空节点 + if begin == end: + return None + + # 找到最大的值和其对应的下标 + max_index = begin + for i in range(begin, end): + if nums[i] > nums[max_index]: + max_index = i + + # 构建当前节点 + root = TreeNode(nums[max_index]) + + # 递归构建左右子树 + root.left = self.traversal(nums, begin, max_index) + root.right = self.traversal(nums, max_index + 1, end) + return root ``` diff --git a/problems/0684.冗余连接.md b/problems/0684.冗余连接.md index c9eb33c4..bfbdeba9 100644 --- a/problems/0684.冗余连接.md +++ b/problems/0684.冗余连接.md @@ -10,6 +10,9 @@ # 684.冗余连接 + +[力扣题目链接](https://leetcode-cn.com/problems/redundant-connection/) + 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。 @@ -140,16 +143,161 @@ public: ## Java ```java +class Solution { + private int n; // 节点数量3 到 1000 + private int[] father; + public Solution() { + n = 1005; + father = new int[n]; + + // 并查集初始化 + for (int i = 0; i < n; ++i) { + father[i] = i; + } + } + + // 并查集里寻根的过程 + private int find(int u) { + if(u == father[u]) { + return u; + } + father[u] = find(father[u]); + return father[u]; + } + + // 将v->u 这条边加入并查集 + private void join(int u, int v) { + u = find(u); + v = find(v); + if (u == v) return ; + father[v] = u; + } + + // 判断 u 和 v是否找到同一个根,本题用不上 + private Boolean same(int u, int v) { + u = find(u); + v = find(v); + return u == v; + } + + public int[] findRedundantConnection(int[][] edges) { + for (int i = 0; i < edges.length; i++) { + if (same(edges[i][0], edges[i][1])) { + return edges[i]; + } else { + join(edges[i][0], edges[i][1]); + } + } + return null; + } +} ``` ## Python ```python + +class Solution: + + def __init__(self): + """ + 初始化 + """ + self.n = 1005 + self.father = [i for i in range(self.n)] + + + def find(self, u): + """ + 并查集里寻根的过程 + """ + if u == self.father[u]: + return u + self.father[u] = self.find(self.father[u]) + return self.father[u] + + def join(self, u, v): + """ + 将v->u 这条边加入并查集 + """ + u = self.find(u) + v = self.find(v) + if u == v : return + self.father[v] = u + pass + + + def same(self, u, v ): + """ + 判断 u 和 v是否找到同一个根,本题用不上 + """ + u = self.find(u) + v = self.find(v) + return u == v + + def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: + for i in range(len(edges)): + if self.same(edges[i][0], edges[i][1]) : + return edges[i] + else : + self.join(edges[i][0], edges[i][1]) + return [] ``` ## Go ```go + +// 全局变量 +var ( + n = 1005 // 节点数量3 到 1000 + father = make([]int, 1005) +) + +// 并查集初始化 +func initialize() { + for i := 0; i < n; i++ { + father[i] = i + } +} + +// 并查集里寻根的过程 +func find(u int) int { + if u == father[u] { + return u + } + father[u] = find(father[u]) + return father[u] +} + +// 将v->u 这条边加入并查集 +func join(u, v int) { + u = find(u) + v = find(v) + if u == v { + return + } + father[v] = u +} + +// 判断 u 和 v是否找到同一个根,本题用不上 +func same(u, v int) bool { + u = find(u) + v = find(v) + return u == v +} + +func findRedundantConnection(edges [][]int) []int { + initialize() + for i := 0; i < len(edges); i++ { + if same(edges[i][0], edges[i][1]) { + return edges[i] + } else { + join(edges[i][0], edges[i][1]) + } + } + return []int{} +} ``` ## JavaScript diff --git a/problems/0685.冗余连接II.md b/problems/0685.冗余连接II.md index 68d0376e..404813f3 100644 --- a/problems/0685.冗余连接II.md +++ b/problems/0685.冗余连接II.md @@ -39,7 +39,7 @@ **这说明题目中的图原本是是一棵树,只不过在不增加节点的情况下多加了一条边!** -还有**若有多个答案,返回最后出现在给定二维数组的答案。**这说明在两天边都可以删除的情况下,要删顺序靠后的! +还有**若有多个答案,返回最后出现在给定二维数组的答案。**这说明在两条边都可以删除的情况下,要删顺序靠后的! 那么有如下三种情况,前两种情况是出现入度为2的点,如图: @@ -58,7 +58,7 @@ 首先先计算节点的入度,代码如下: -```CPP +```cpp int inDegree[N] = {0}; // 记录节点入度 n = edges.size(); // 边的数量 for (int i = 0; i < n; i++) { @@ -70,7 +70,7 @@ for (int i = 0; i < n; i++) { 代码如下: -```CPP +```cpp vector vec; // 记录入度为2的边(如果有的话就两条边) // 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案 for (int i = n - 1; i >= 0; i--) { @@ -112,7 +112,7 @@ vector getRemoveEdge(const vector>& edges) 本题C++代码如下:(详细注释了) -```CPP +```cpp class Solution { private: static const int N = 1010; // 如题:二维数组大小的在3到1000范围内 @@ -174,7 +174,7 @@ public: inDegree[edges[i][1]]++; // 统计入度 } vector vec; // 记录入度为2的边(如果有的话就两条边) - // 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案 + // 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案 for (int i = n - 1; i >= 0; i--) { if (inDegree[edges[i][1]] == 2) { vec.push_back(i); @@ -203,16 +203,313 @@ public: ## Java ```java + +class Solution { + + private static final int N = 1010; // 如题:二维数组大小的在3到1000范围内 + private int[] father; + public Solution() { + father = new int[N]; + + // 并查集初始化 + for (int i = 0; i < N; ++i) { + father[i] = i; + } + } + + // 并查集里寻根的过程 + private int find(int u) { + if(u == father[u]) { + return u; + } + father[u] = find(father[u]); + return father[u]; + } + + // 将v->u 这条边加入并查集 + private void join(int u, int v) { + u = find(u); + v = find(v); + if (u == v) return ; + father[v] = u; + } + + // 判断 u 和 v是否找到同一个根,本题用不上 + private Boolean same(int u, int v) { + u = find(u); + v = find(v); + return u == v; + } + + /** + * 初始化并查集 + */ + private void initFather() { + // 并查集初始化 + for (int i = 0; i < N; ++i) { + father[i] = i; + } + } + + /** + * 在有向图里找到删除的那条边,使其变成树 + * @param edges + * @return 要删除的边 + */ + private int[] getRemoveEdge(int[][] edges) { + initFather(); + for(int i = 0; i < edges.length; i++) { + if(same(edges[i][0], edges[i][1])) { // 构成有向环了,就是要删除的边 + return edges[i]; + } + join(edges[i][0], edges[i][1]); + } + return null; + } + + /** + * 删一条边之后判断是不是树 + * @param edges + * @param deleteEdge 要删除的边 + * @return true: 是树, false: 不是树 + */ + private Boolean isTreeAfterRemoveEdge(int[][] edges, int deleteEdge) + { + initFather(); + for(int i = 0; i < edges.length; i++) + { + if(i == deleteEdge) continue; + if(same(edges[i][0], edges[i][1])) { // 构成有向环了,一定不是树 + return false; + } + join(edges[i][0], edges[i][1]); + } + return true; + } + + public int[] findRedundantDirectedConnection(int[][] edges) { + int[] inDegree = new int[N]; + for(int i = 0; i < edges.length; i++) + { + // 入度 + inDegree[ edges[i][1] ] += 1; + } + + // 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案 + ArrayList twoDegree = new ArrayList(); + for(int i = edges.length - 1; i >= 0; i--) + { + if(inDegree[edges[i][1]] == 2) { + twoDegree.add(i); + } + } + + // 处理图中情况1 和 情况2 + // 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树 + if(!twoDegree.isEmpty()) + { + if(isTreeAfterRemoveEdge(edges, twoDegree.get(0))) { + return edges[ twoDegree.get(0)]; + } + return edges[ twoDegree.get(1)]; + } + + // 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了 + return getRemoveEdge(edges); + } +} ``` ## Python ```python + +class Solution: + + def __init__(self): + self.n = 1010 + self.father = [i for i in range(self.n)] + + + def find(self, u: int): + """ + 并查集里寻根的过程 + """ + if u == self.father[u]: + return u + self.father[u] = self.find(self.father[u]) + return self.father[u] + + def join(self, u: int, v: int): + """ + 将v->u 这条边加入并查集 + """ + u = self.find(u) + v = self.find(v) + if u == v : return + self.father[v] = u + pass + + + def same(self, u: int, v: int ): + """ + 判断 u 和 v是否找到同一个根,本题用不上 + """ + u = self.find(u) + v = self.find(v) + return u == v + + def init_father(self): + self.father = [i for i in range(self.n)] + pass + + def getRemoveEdge(self, edges: List[List[int]]) -> List[int]: + """ + 在有向图里找到删除的那条边,使其变成树 + """ + + self.init_father() + for i in range(len(edges)): + if self.same(edges[i][0], edges[i][1]): # 构成有向环了,就是要删除的边 + return edges[i] + self.join(edges[i][0], edges[i][1]); + return [] + + def isTreeAfterRemoveEdge(self, edges: List[List[int]], deleteEdge: int) -> bool: + """ + 删一条边之后判断是不是树 + """ + + self.init_father() + for i in range(len(edges)): + if i == deleteEdge: continue + if self.same(edges[i][0], edges[i][1]): # 构成有向环了,一定不是树 + return False + self.join(edges[i][0], edges[i][1]); + return True + + def findRedundantDirectedConnection(self, edges: List[List[int]]) -> List[int]: + inDegree = [0 for i in range(self.n)] + + for i in range(len(edges)): + inDegree[ edges[i][1] ] += 1 + + # 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案 + towDegree = [] + for i in range(len(edges))[::-1]: + if inDegree[edges[i][1]] == 2 : + towDegree.append(i) + + # 处理图中情况1 和 情况2 + # 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树 + if len(towDegree) > 0: + if(self.isTreeAfterRemoveEdge(edges, towDegree[0])) : + return edges[towDegree[0]] + return edges[towDegree[1]] + + # 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了 + return self.getRemoveEdge(edges) ``` ## Go ```go + +// 全局变量 +var ( + n = 1010// 节点数量3 到 1000 + father = make([]int, n) +) + +// 并查集初始化 +func initialize() { + for i := 0; i < n; i++ { + father[i] = i + } +} + +// 并查集里寻根的过程 +func find(u int) int { + if u == father[u] { + return u + } + father[u] = find(father[u]) + return father[u] +} + +// 将v->u 这条边加入并查集 +func join(u, v int) { + u = find(u) + v = find(v) + if u == v { + return + } + father[v] = u +} + +// 判断 u 和 v是否找到同一个根,本题用不上 +func same(u, v int) bool { + u = find(u) + v = find(v) + return u == v +} + +// getRemoveEdge 在有向图里找到删除的那条边,使其变成树 +func getRemoveEdge(edges [][]int) []int { + initialize() + for i := 0; i < len(edges); i++ { // 遍历所有的边 + if same(edges[i][0], edges[i][1]) { // 构成有向环了,就是要删除的边 + return edges[i] + } + join(edges[i][0], edges[i][1]) + } + return []int{} +} + +// isTreeAfterRemoveEdge 删一条边之后判断是不是树 +func isTreeAfterRemoveEdge(edges [][]int, deleteEdge int) bool { + initialize() + for i := 0; i < len(edges); i++ { + if i == deleteEdge { + continue + } + if same(edges[i][0], edges[i][1]) { // 构成有向环了,一定不是树 + return false + } + join(edges[i][0], edges[i][1]) + } + return true +} + +func findRedundantDirectedConnection(edges [][]int) []int { + inDegree := make([]int, len(father)) + for i := 0; i < len(edges); i++ { + // 统计入度 + inDegree[edges[i][1]] += 1 + } + // 记录入度为2的边(如果有的话就两条边) + // 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案 + twoDegree := make([]int, 0) + for i := len(edges) - 1; i >= 0; i-- { + if inDegree[edges[i][1]] == 2 { + twoDegree = append(twoDegree, i) + } + } + + // 处理图中情况1 和 情况2 + // 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树 + if len(twoDegree) > 0 { + if isTreeAfterRemoveEdge(edges, twoDegree[0]) { + return edges[twoDegree[0]] + } + return edges[twoDegree[1]] + } + + // 处理图中情况3 + // 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了 + return getRemoveEdge(edges) +} + ``` ## JavaScript diff --git a/problems/0724.寻找数组的中心索引.md b/problems/0724.寻找数组的中心索引.md index b4115893..991ce647 100644 --- a/problems/0724.寻找数组的中心索引.md +++ b/problems/0724.寻找数组的中心索引.md @@ -9,6 +9,8 @@ # 724.寻找数组的中心下标 +[力扣题目链接](https://leetcode-cn.com/problems/find-pivot-index/) + 给你一个整数数组 nums ,请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。 @@ -87,15 +89,15 @@ class Solution { } ``` -## Python +## Python3 -```python3 +```python class Solution: def pivotIndex(self, nums: List[int]) -> int: numSum = sum(nums) #数组总和 leftSum = 0 for i in range(len(nums)): - if numSum - leftSum -nums[i] == leftSum: #左右和相等 + if numSum - leftSum -nums[i] == leftSum: #左右和相等 return i leftSum += nums[i] return -1 @@ -104,6 +106,24 @@ class Solution: ## Go ```go +func pivotIndex(nums []int) int { + sum := 0 + for _, v := range nums { + sum += v; + } + + leftSum := 0 // 中心索引左半和 + rightSum := 0 // 中心索引右半和 + for i := 0; i < len(nums); i++ { + leftSum += nums[i] + rightSum = sum - leftSum + nums[i] + if leftSum == rightSum{ + return i + } + } + return -1 +} + ``` ## JavaScript diff --git a/problems/0968.监控二叉树.md b/problems/0968.监控二叉树.md index a5fa71a7..384c9a78 100644 --- a/problems/0968.监控二叉树.md +++ b/problems/0968.监控二叉树.md @@ -347,24 +347,57 @@ class Solution { Python: ```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right class Solution: def minCameraCover(self, root: TreeNode) -> int: + # Greedy Algo: + # 从下往上安装摄像头:跳过leaves这样安装数量最少,局部最优 -> 全局最优 + # 先给leaves的父节点安装,然后每隔两层节点安装一个摄像头,直到Head + # 0: 该节点未覆盖 + # 1: 该节点有摄像头 + # 2: 该节点有覆盖 + result = 0 - def traversal(cur): + # 从下往上遍历:后序(左右中) + def traversal(curr: TreeNode) -> int: nonlocal result - if not cur: - return 2 - left = traversal(cur.left) - right = traversal(cur.right) - if left == 2 and right == 2: + + if not curr: return 2 + left = traversal(curr.left) + right = traversal(curr.right) + + # Case 1: + # 左右节点都有覆盖 + if left == 2 and right == 2: return 0 - elif left == 0 or right == 0: + + # Case 2: + # left == 0 && right == 0 左右节点无覆盖 + # left == 1 && right == 0 左节点有摄像头,右节点无覆盖 + # left == 0 && right == 1 左节点有无覆盖,右节点摄像头 + # left == 0 && right == 2 左节点无覆盖,右节点覆盖 + # left == 2 && right == 0 左节点覆盖,右节点无覆盖 + elif left == 0 or right == 0: result += 1 return 1 + + # Case 3: + # left == 1 && right == 2 左节点有摄像头,右节点有覆盖 + # left == 2 && right == 1 左节点有覆盖,右节点有摄像头 + # left == 1 && right == 1 左右节点都有摄像头 elif left == 1 or right == 1: return 2 - else: return -1 - if traversal(root) == 0: result += 1 + + # 其他情况前段代码均已覆盖 + + if traversal(root) == 0: + result += 1 + return result ``` Go: diff --git a/problems/1049.最后一块石头的重量II.md b/problems/1049.最后一块石头的重量II.md index 25299f14..795d923c 100644 --- a/problems/1049.最后一块石头的重量II.md +++ b/problems/1049.最后一块石头的重量II.md @@ -219,7 +219,28 @@ func max(a, b int) int { } ``` +JavaScript版本 +```javascript +/** + * @param {number[]} stones + * @return {number} + */ +var lastStoneWeightII = function (stones) { + let sum = stones.reduce((s, n) => s + n); + + let dpLen = Math.floor(sum / 2); + let dp = new Array(dpLen + 1).fill(0); + + for (let i = 0; i < stones.length; ++i) { + for (let j = dpLen; j >= stones[i]; --j) { + dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]); + } + } + + return sum - dp[dpLen] - dp[dpLen]; +}; +``` ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) diff --git a/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md b/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md index 31a5e448..2eb253ba 100644 --- a/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md +++ b/problems/为了绝杀编辑距离,卡尔做了三步铺垫.md @@ -167,7 +167,33 @@ else { Java: - +```java +class Solution { + public int minDistance(String word1, String word2) { + int m = word1.length(); + int n = word2.length(); + int[][] dp = new int[m+1][n+1]; + for(int i = 1; i <= m; i++){ + dp[i][0] = i; + } + for(int i = 1; i <= n; i++){ + dp[0][i] = i; + } + for(int i = 1; i <= m; i++){ + for(int j = 1; j <= n; j++){ + int left = dp[i][j-1]+1; + int mid = dp[i-1][j-1]; + int right = dp[i-1][j]+1; + if(word1.charAt(i-1) != word2.charAt(j-1)){ + mid ++; + } + dp[i][j] = Math.min(left,Math.min(mid,right)); + } + } + return dp[m][n]; + } +} +``` Python: diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index 2bcded70..7d04b514 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -34,7 +34,7 @@ leetcode上没有纯01背包的问题,都是01背包应用方面的题目, ## 01 背包 -有N件物品和一个最多能被重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。 +有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。 ![动态规划-背包问题](https://img-blog.csdnimg.cn/20210117175428387.jpg)