diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index 271822dc..84ce7750 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -9,7 +9,7 @@ # 28. 实现 strStr() -[力扣题目链接](https://leetcode.cn/problems/implement-strstr/) +[力扣题目链接](https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/) 实现 strStr() 函数。 @@ -699,7 +699,7 @@ class Solution(object): if haystack[i:i+n]==needle: return i return -1 -``` +``` ```python // 方法一 class Solution: diff --git a/problems/0031.下一个排列.md b/problems/0031.下一个排列.md index a33821b8..fbea1c19 100644 --- a/problems/0031.下一个排列.md +++ b/problems/0031.下一个排列.md @@ -160,73 +160,34 @@ class Solution { ``` ## Python ->直接使用sorted()不符合题意 +>直接使用sorted()会开辟新的空间并返回一个新的list,故补充一个原地反转函数 ```python class Solution: - def nextPermutation(self, nums: List[int]) -> None: - """ - Do not return anything, modify nums in-place instead. - """ - for i in range(len(nums)-1, -1, -1): - for j in range(len(nums)-1, i, -1): - if nums[j] > nums[i]: - nums[j], nums[i] = nums[i], nums[j] - nums[i+1:len(nums)] = sorted(nums[i+1:len(nums)]) - return - nums.sort() -``` ->另一种思路 -```python -class Solution: - ''' - 抛砖引玉:因题目要求“必须原地修改,只允许使用额外常数空间”,python内置sorted函数以及数组切片+sort()无法使用。 - 故选择另一种算法暂且提供一种python思路 - ''' def nextPermutation(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ length = len(nums) - for i in range(length-1, 0, -1): - if nums[i-1] < nums[i]: - for j in range(length-1, 0, -1): - if nums[j] > nums[i-1]: - nums[i-1], nums[j] = nums[j], nums[i-1] - break - self.reverse(nums, i, length-1) - break - if n == 1: - # 若正常结束循环,则对原数组直接翻转 - self.reverse(nums, 0, length-1) - - def reverse(self, nums: List[int], low: int, high: int) -> None: - while low < high: - nums[low], nums[high] = nums[high], nums[low] - low += 1 - high -= 1 -``` ->上一版本简化版 -```python -class Solution(object): - def nextPermutation(self, nums: List[int]) -> None: - n = len(nums) - i = n-2 - while i >= 0 and nums[i] >= nums[i+1]: - i -= 1 - - if i > -1: // i==-1,不存在下一个更大的排列 - j = n-1 - while j >= 0 and nums[j] <= nums[i]: - j -= 1 - nums[i], nums[j] = nums[j], nums[i] + for i in range(length - 1, -1, -1): + for j in range(length - 1, i, -1): + if nums[j] > nums[i]: + nums[j], nums[i] = nums[i], nums[j] + self.reverse(nums, i + 1, length - 1) + return + self.reverse(nums, 0, length - 1) - start, end = i+1, n-1 - while start < end: - nums[start], nums[end] = nums[end], nums[start] - start += 1 - end -= 1 - - return nums + def reverse(self, nums: List[int], left: int, right: int) -> None: + while left < right: + nums[left], nums[right] = nums[right], nums[left] + left += 1 + right -= 1 + +""" +265 / 265 个通过测试用例 +状态:通过 +执行用时: 36 ms +内存消耗: 14.9 MB +""" ``` ## Go diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 99577f0c..417f4a6d 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -258,40 +258,45 @@ public: **使用标记数组** ```Java class Solution { - List> lists = new ArrayList<>(); - Deque deque = new LinkedList<>(); - int sum = 0; + LinkedList path = new LinkedList<>(); + List> ans = new ArrayList<>(); + boolean[] used; + int sum = 0; - public List> combinationSum2(int[] candidates, int target) { - //为了将重复的数字都放到一起,所以先进行排序 - Arrays.sort(candidates); - //加标志数组,用来辅助判断同层节点是否已经遍历 - boolean[] flag = new boolean[candidates.length]; - backTracking(candidates, target, 0, flag); - return lists; - } + public List> combinationSum2(int[] candidates, int target) { + used = new boolean[candidates.length]; + // 加标志数组,用来辅助判断同层节点是否已经遍历 + Arrays.fill(used, false); + // 为了将重复的数字都放到一起,所以先进行排序 + Arrays.sort(candidates); + backTracking(candidates, target, 0); + return ans; + } - public void backTracking(int[] arr, int target, int index, boolean[] flag) { - if (sum == target) { - lists.add(new ArrayList(deque)); - return; - } - for (int i = index; i < arr.length && arr[i] + sum <= target; i++) { - //出现重复节点,同层的第一个节点已经被访问过,所以直接跳过 - if (i > 0 && arr[i] == arr[i - 1] && !flag[i - 1]) { - continue; - } - flag[i] = true; - sum += arr[i]; - deque.push(arr[i]); - //每个节点仅能选择一次,所以从下一位开始 - backTracking(arr, target, i + 1, flag); - int temp = deque.pop(); - flag[i] = false; - sum -= temp; - } + private void backTracking(int[] candidates, int target, int startIndex) { + if (sum == target) { + ans.add(new ArrayList(path)); } + for (int i = startIndex; i < candidates.length; i++) { + if (sum + candidates[i] > target) { + break; + } + // 出现重复节点,同层的第一个节点已经被访问过,所以直接跳过 + if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) { + continue; + } + used[i] = true; + sum += candidates[i]; + path.add(candidates[i]); + // 每个节点仅能选择一次,所以从下一位开始 + backTracking(candidates, target, i + 1); + used[i] = false; + sum -= candidates[i]; + path.removeLast(); + } + } } + ``` **不使用标记数组** ```Java diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md index ce07395a..5a4ff154 100644 --- a/problems/0046.全排列.md +++ b/problems/0046.全排列.md @@ -331,7 +331,7 @@ var permute = function(nums) { ``` -## TypeScript +### TypeScript ```typescript function permute(nums: number[]): number[][] { diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md index c7326b63..6b81225c 100644 --- a/problems/0063.不同路径II.md +++ b/problems/0063.不同路径II.md @@ -210,24 +210,54 @@ public: ```java class Solution { public int uniquePathsWithObstacles(int[][] obstacleGrid) { - int n = obstacleGrid.length, m = obstacleGrid[0].length; - int[][] dp = new int[n][m]; - - for (int i = 0; i < m; i++) { - if (obstacleGrid[0][i] == 1) break; //一旦遇到障碍,后续都到不了 - dp[0][i] = 1; + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + int[][] dp = new int[m][n]; + + //如果在起点或终点出现了障碍,直接返回0 + if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) { + return 0; } - for (int i = 0; i < n; i++) { - if (obstacleGrid[i][0] == 1) break; ////一旦遇到障碍,后续都到不了 - dp[i][0] = 1; + + for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) { + dp[i][0] = 1; } - for (int i = 1; i < n; i++) { - for (int j = 1; j < m; j++) { - if (obstacleGrid[i][j] == 1) continue; - dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) { + dp[0][j] = 1; + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = (obstacleGrid[i][j] == 0) ? dp[i - 1][j] + dp[i][j - 1] : 0; } } - return dp[n - 1][m - 1]; + return dp[m - 1][n - 1]; + } +} +``` + +```java +// 空间优化版本 +class Solution { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + int[] dp = new int[n]; + + for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) { + dp[j] = 1; + } + + for (int i = 1; i < m; i++) { + for (int j = 0; j < n; j++) { + if (obstacleGrid[i][j] == 1) { + dp[j] = 0; + } else if (j != 0) { + dp[j] += dp[j - 1]; + } + } + } + return dp[n - 1]; } } ``` diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md index 30c3642f..0a6acf7f 100644 --- a/problems/0070.爬楼梯.md +++ b/problems/0070.爬楼梯.md @@ -213,22 +213,6 @@ public: ### Java -```Java -class Solution { - public int climbStairs(int n) { - // 跟斐波那契数列一样 - if(n <= 2) return n; - int a = 1, b = 2, sum = 0; - - for(int i = 3; i <= n; i++){ - sum = a + b; - a = b; - b = sum; - } - return b; - } -} -``` ```java // 常规方式 @@ -241,15 +225,22 @@ public int climbStairs(int n) { } return dp[n]; } +``` + +```Java // 用变量记录代替数组 -public int climbStairs(int n) { - int a = 0, b = 1, c = 0; // 默认需要1次 - for (int i = 1; i <= n; i++) { - c = a + b; // f(i - 1) + f(n - 2) - a = b; // 记录上一轮的值 - b = c; // 向后步进1个数 +class Solution { + public int climbStairs(int n) { + if(n <= 2) return n; + int a = 1, b = 2, sum = 0; + + for(int i = 3; i <= n; i++){ + sum = a + b; // f(i - 1) + f(i - 2) + a = b; // 记录f(i - 1),即下一轮的f(i - 2) + b = sum; // 记录f(i),即下一轮的f(i - 1) + } + return b; } - return c; } ``` diff --git a/problems/0078.子集.md b/problems/0078.子集.md index 3e98311e..a9ffd696 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -180,10 +180,6 @@ class Solution { List> result = new ArrayList<>();// 存放符合条件结果的集合 LinkedList path = new LinkedList<>();// 用来存放符合条件结果 public List> subsets(int[] nums) { - if (nums.length == 0){ - result.add(new ArrayList<>()); - return result; - } subsetsHelper(nums, 0); return result; } diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index d8d4e2f8..b79fd9cb 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -499,7 +499,7 @@ class solution: if not cur_node.left and not cur_node.right: if remain == 0: result.append(path[:]) - return + return if cur_node.left: path.append(cur_node.left.val) @@ -508,7 +508,7 @@ class solution: if cur_node.right: path.append(cur_node.right.val) - traversal(cur_node.right, remain-cur_node.left.val) + traversal(cur_node.right, remain-cur_node.right.val) path.pop() result, path = [], [] diff --git a/problems/0135.分发糖果.md b/problems/0135.分发糖果.md index 242664f0..03360dbc 100644 --- a/problems/0135.分发糖果.md +++ b/problems/0135.分发糖果.md @@ -135,25 +135,22 @@ class Solution { 2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大 */ public int candy(int[] ratings) { - int[] candyVec = new int[ratings.length]; + int len = ratings.length; + int[] candyVec = new int[len]; candyVec[0] = 1; - for (int i = 1; i < ratings.length; i++) { - if (ratings[i] > ratings[i - 1]) { - candyVec[i] = candyVec[i - 1] + 1; - } else { - candyVec[i] = 1; - } + for (int i = 1; i < len; i++) { + candyVec[i] = (ratings[i] > ratings[i - 1]) ? candyVec[i - 1] + 1 : 1; } - for (int i = ratings.length - 2; i >= 0; i--) { + for (int i = len - 2; i >= 0; i--) { if (ratings[i] > ratings[i + 1]) { candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1); } } int ans = 0; - for (int s : candyVec) { - ans += s; + for (int num : candyVec) { + ans += num; } return ans; } diff --git a/problems/0200.岛屿数量.广搜版.md b/problems/0200.岛屿数量.广搜版.md index d43d6183..f70ea50c 100644 --- a/problems/0200.岛屿数量.广搜版.md +++ b/problems/0200.岛屿数量.广搜版.md @@ -144,3 +144,50 @@ public: }; ``` + +## 其他语言版本 + +### Java + +```java +class Solution { + + boolean[][] visited; + int[][] move = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int numIslands(char[][] grid) { + int res = 0; + visited = new boolean[grid.length][grid[0].length]; + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(!visited[i][j] && grid[i][j] == '1') { + bfs(grid, i, j); + res++; + } + } + } + return res; + } + + //将这片岛屿上的所有陆地都访问到 + public void bfs(char[][] grid, int y, int x) { + Deque queue = new ArrayDeque<>(); + queue.offer(new int[]{y, x}); + visited[y][x] = true; + while(!queue.isEmpty()) { + int[] cur = queue.poll(); + int m = cur[0]; + int n = cur[1]; + for(int i = 0; i < 4; i++) { + int nexty = m + move[i][0]; + int nextx = n + move[i][1]; + if(nextx < 0 || nexty == grid.length || nexty < 0 || nextx == grid[0].length) continue; + if(!visited[nexty][nextx] && grid[nexty][nextx] == '1') { + queue.offer(new int[]{nexty, nextx}); + visited[nexty][nextx] = true; //只要加入队列就标记为访问 + } + } + } + } +} +``` diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 1ef278ff..964facee 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -260,6 +260,37 @@ class Solution { } } } + +// 上面剪枝 i <= 9 - (k - path.size()) + 1; 如果还是不清楚 +// 也可以改为 if (path.size() > k) return; 执行效率上是一样的 +class Solution { + LinkedList path = new LinkedList<>(); + List> ans = new ArrayList<>(); + public List> combinationSum3(int k, int n) { + build(k, n, 1, 0); + return ans; + } + + private void build(int k, int n, int startIndex, int sum) { + + if (sum > n) return; + + if (path.size() > k) return; + + if (sum == n && path.size() == k) { + ans.add(new ArrayList<>(path)); + return; + } + + for(int i = startIndex; i <= 9; i++) { + path.add(i); + sum += i; + build(k, n, i + 1, sum); + sum -= i; + path.removeLast(); + } + } +} ``` 其他方法 diff --git a/problems/0337.打家劫舍III.md b/problems/0337.打家劫舍III.md index 20b458e9..295f19fe 100644 --- a/problems/0337.打家劫舍III.md +++ b/problems/0337.打家劫舍III.md @@ -191,7 +191,7 @@ public: vector left = robTree(cur->left); vector right = robTree(cur->right); // 偷cur,那么就不能偷左右节点。 - int val1 = cur->val + left[1] + right[1]; + int val1 = cur->val + left[0] + right[0]; // 不偷cur,那么可以偷也可以不偷左右节点,则取较大的情况 int val2 = max(left[0], left[1]) + max(right[0], right[1]); return {val2, val1}; diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md index d15ed2d0..fef5e594 100644 --- a/problems/0376.摆动序列.md +++ b/problems/0376.摆动序列.md @@ -269,18 +269,23 @@ class Solution: **贪心** ```golang func wiggleMaxLength(nums []int) int { - var count, preDiff, curDiff int //初始化默认为0 - count = 1 // 初始化为1,因为最小的序列是1个数 - if len(nums) < 2 { - return count + n := len(nums) + if n < 2 { + return n } - for i := 0; i < len(nums)-1; i++ { - curDiff = nums[i+1] - nums[i] - if (curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0) { - count++ + ans := 1 + prevDiff := nums[1] - nums[0] + if prevDiff != 0 { + ans = 2 + } + for i := 2; i < n; i++ { + diff := nums[i] - nums[i-1] + if diff > 0 && prevDiff <= 0 || diff < 0 && prevDiff >= 0 { + ans++ + prevDiff = diff } } - return count + return ans } ``` diff --git a/problems/0452.用最少数量的箭引爆气球.md b/problems/0452.用最少数量的箭引爆气球.md index c571a235..91e340be 100644 --- a/problems/0452.用最少数量的箭引爆气球.md +++ b/problems/0452.用最少数量的箭引爆气球.md @@ -137,29 +137,21 @@ public: ### Java ```java /** -时间复杂度 : O(NlogN) 排序需要 O(NlogN) 的复杂度 - -空间复杂度 : O(logN) java所使用的内置函数用的是快速排序需要 logN 的空间 -*/ + * 时间复杂度 : O(NlogN) 排序需要 O(NlogN) 的复杂度 + * 空间复杂度 : O(logN) java所使用的内置函数用的是快速排序需要 logN 的空间 + */ class Solution { public int findMinArrowShots(int[][] points) { - if (points.length == 0) return 0; - //用x[0] - y[0] 会大于2147483647 造成整型溢出 - Arrays.sort(points, (x, y) -> Integer.compare(x[0], y[0])); - //count = 1 因为最少需要一个箭来射击第一个气球 - int count = 1; - //重叠气球的最小右边界 - int leftmostRightBound = points[0][1]; + // 根据气球直径的开始坐标从小到大排序 + // 使用Integer内置比较方法,不会溢出 + Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0])); + + int count = 1; // points 不为空至少需要一支箭 for (int i = 1; i < points.length; i++) { - //如果下一个气球的左边界大于最小右边界 - for(int i = 1; i < points.length; i++){ - if (points[i][0] > leftmostRightBound ) { - //增加一次射击 - count++; - leftmostRightBound = points[i][1]; - //不然就更新最小右边界 - } else { - leftmostRightBound = Math.min(leftmostRightBound , points[i][1]); + if (points[i][0] > points[i - 1][1]) { // 气球i和气球i-1不挨着,注意这里不是>= + count++; // 需要一支箭 + } else { // 气球i和气球i-1挨着 + points[i][1] = Math.min(points[i][1], points[i - 1][1]); // 更新重叠气球最小右边界 } } return count; diff --git a/problems/0463.岛屿的周长.md b/problems/0463.岛屿的周长.md index 3dc69f20..a881cd7c 100644 --- a/problems/0463.岛屿的周长.md +++ b/problems/0463.岛屿的周长.md @@ -179,6 +179,25 @@ class Solution: ``` Go: +```go +func islandPerimeter(grid [][]int) int { + m, n := len(grid), len(grid[0]) + res := 0 + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + if grid[i][j] == 1 { + res += 4 + // 上下左右四个方向 + if i > 0 && grid[i-1][j] == 1 {res--} // 上边有岛屿 + if i < m-1 && grid[i+1][j] == 1 {res--} // 下边有岛屿 + if j > 0 && grid[i][j-1] == 1 {res--} // 左边有岛屿 + if j < n-1 && grid[i][j+1] == 1 {res--} // 右边有岛屿 + } + } + } + return res +} +``` JavaScript: ```javascript diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index 9611df99..af1cbd74 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -233,7 +233,7 @@ class Solution: else: # 逐一处理节点 cur = stack.pop() if pre: # 当前节点和前节点的值的差值 - result = min(result, cur.val - pre.val) + result = min(result, abs(cur.val - pre.val)) pre = cur cur = cur.right return result diff --git a/problems/0695.岛屿的最大面积.md b/problems/0695.岛屿的最大面积.md index e5567aec..447a374c 100644 --- a/problems/0695.岛屿的最大面积.md +++ b/problems/0695.岛屿的最大面积.md @@ -167,3 +167,111 @@ public: }; ``` + +# 其它语言版本 + +## Python +### BFS +```python +class Solution: + def __init__(self): + self.count = 0 + + def maxAreaOfIsland(self, grid: List[List[int]]) -> int: + # 与200.独立岛屿不同的是:此题grid列表内是int!!! + + # BFS + if not grid: return 0 + + m, n = len(grid), len(grid[0]) + visited = [[False for i in range(n)] for j in range(m)] + + result = 0 + for i in range(m): + for j in range(n): + if not visited[i][j] and grid[i][j] == 1: + # 每一个新岛屿 + self.count = 0 + print(f'{self.count}') + self.bfs(grid, visited, i, j) + result = max(result, self.count) + + return result + + def bfs(self, grid, visited, i, j): + self.count += 1 + visited[i][j] = True + + queue = collections.deque([(i, j)]) + while queue: + x, y = queue.popleft() + for new_x, new_y in [(x + 1, y), (x - 1, y), (x, y - 1), (x, y + 1)]: + if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]) and not visited[new_x][new_y] and grid[new_x][new_y] == 1: + visited[new_x][new_y] = True + self.count += 1 + queue.append((new_x, new_y)) +``` +### DFS +```python +class Solution: + def __init__(self): + self.count = 0 + + def maxAreaOfIsland(self, grid: List[List[int]]) -> int: + # DFS + if not grid: return 0 + + m, n = len(grid), len(grid[0]) + visited = [[False for _ in range(n)] for _ in range(m)] + + result = 0 + for i in range(m): + for j in range(n): + if not visited[i][j] and grid[i][j] == 1: + self.count = 0 + self.dfs(grid, visited, i, j) + result = max(result, self.count) + return result + + def dfs(self, grid, visited, x, y): + if visited[x][y] or grid[x][y] == 0: + return + visited[x][y] = True + self.count += 1 + for new_x, new_y in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]: + if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]): + self.dfs(grid, visited, new_x, new_y) +``` + + + +## Java + +这里使用深度优先搜索 DFS 来完成本道题目。我们使用 DFS 计算一个岛屿的面积,同时维护计算过的最大的岛屿面积。同时,为了避免对岛屿重复计算,我们在 DFS 的时候对岛屿进行 “淹没” 操作,即将岛屿所占的地方置为 0。 + +```java +public int maxAreaOfIsland(int[][] grid) { + int res = 0; + for(int i = 0;i < grid.length;i++){ + for(int j = 0;j < grid[0].length;j++){ + //每遇到一个岛屿就计算这个岛屿的面积同时”淹没“这个岛屿 + if(grid[i][j] == 1){ + //每次计算一个岛屿的面积都要与res比较,维护最大的岛屿面积作为最后的答案 + res = Math.max(res,dfs(grid,i,j)); + } + } + } + return res; +} +public int dfs(int[][] grid,int i,int j){ + //搜索边界:i,j超过grid的范围或者当前元素为0,即当前所在的地方已经是海洋 + if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0; + //淹没土地,防止后续被重复计算 + grid[i][j] = 0; + //递归的思路:要求当前土地(i,j)所在的岛屿的面积,则等于1加上下左右相邻的土地的总面积 + return 1 + dfs(grid,i - 1,j) + + dfs(grid,i + 1,j) + + dfs(grid,i,j + 1) + + dfs(grid,i,j - 1); +} +``` diff --git a/problems/0746.使用最小花费爬楼梯.md b/problems/0746.使用最小花费爬楼梯.md index 92fb2920..9d3bd7fa 100644 --- a/problems/0746.使用最小花费爬楼梯.md +++ b/problems/0746.使用最小花费爬楼梯.md @@ -66,7 +66,7 @@ 所以初始化代码为: -``` +```CPP vector dp(cost.size()); dp[0] = cost[0]; dp[1] = cost[1]; @@ -201,15 +201,32 @@ public: ### Java + ```Java +// 方式一:第一步支付费用 class Solution { public int minCostClimbingStairs(int[] cost) { - if (cost == null || cost.length == 0) { - return 0; - } - if (cost.length == 1) { - return cost[0]; + int len = cost.length; + int[] dp = new int[len + 1]; + + // 从下标为 0 或下标为 1 的台阶开始,因此支付费用为0 + dp[0] = 0; + dp[1] = 0; + + // 计算到达每一层台阶的最小费用 + for (int i = 2; i <= len; i++) { + dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); } + + return dp[len]; + } +} +``` + +```Java +// 方式二:第一步不支付费用 +class Solution { + public int minCostClimbingStairs(int[] cost) { int[] dp = new int[cost.length]; dp[0] = cost[0]; dp[1] = cost[1]; diff --git a/problems/0797.所有可能的路径.md b/problems/0797.所有可能的路径.md index a51590f2..f1f867f7 100644 --- a/problems/0797.所有可能的路径.md +++ b/problems/0797.所有可能的路径.md @@ -296,5 +296,29 @@ public: ### Java ### Python +``` +class Solution: + def __init__(self): + self.result = [] + self.path = [0] + + def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]: + if not graph: return [] + + self.dfs(graph, 0) + return self.result + + def dfs(self, graph, root: int): + if root == len(graph) - 1: # 成功找到一条路径时 + # ***Python的list是mutable类型*** + # ***回溯中必须使用Deep Copy*** + self.result.append(self.path[:]) + return + + for node in graph[root]: # 遍历节点n的所有后序节点 + self.path.append(node) + self.dfs(graph, node) + self.path.pop() # 回溯 +``` ### Go diff --git a/problems/0968.监控二叉树.md b/problems/0968.监控二叉树.md index b17ff080..717112a7 100644 --- a/problems/0968.监控二叉树.md +++ b/problems/0968.监控二叉树.md @@ -71,7 +71,7 @@ 后序遍历代码如下: -``` +```CPP int traversal(TreeNode* cur) { // 空节点,该节点有覆盖 @@ -124,7 +124,7 @@ int traversal(TreeNode* cur) { 代码如下: -``` +```CPP // 空节点,该节点有覆盖 if (cur == NULL) return 2; ``` @@ -143,7 +143,7 @@ if (cur == NULL) return 2; 代码如下: -``` +```CPP // 左右节点都有覆盖 if (left == 2 && right == 2) return 0; ``` @@ -163,7 +163,7 @@ left == 2 && right == 0 左节点覆盖,右节点无覆盖 此时摄像头的数量要加一,并且return 1,代表中间节点放摄像头。 代码如下: -``` +```CPP if (left == 0 || right == 0) { result++; return 1; @@ -180,7 +180,7 @@ left == 1 && right == 1 左右节点都有摄像头 代码如下: -``` +```CPP if (left == 1 || right == 1) return 2; ``` @@ -198,7 +198,7 @@ if (left == 1 || right == 1) return 2; 所以递归结束之后,还要判断根节点,如果没有覆盖,result++,代码如下: -``` +```CPP int minCameraCover(TreeNode* root) { result = 0; if (traversal(root) == 0) { // root 无覆盖 diff --git a/problems/1356.根据数字二进制下1的数目排序.md b/problems/1356.根据数字二进制下1的数目排序.md index 5ca73607..e97748cb 100644 --- a/problems/1356.根据数字二进制下1的数目排序.md +++ b/problems/1356.根据数字二进制下1的数目排序.md @@ -170,6 +170,39 @@ class Solution: ## Go ```go +func sortByBits(arr []int) []int { + var tmp int + for i := 0; i < len(arr); i++ { + for j := i+1; j < len(arr); j++ { + // 冒泡排序的手法,但是排序的规则从比大小变成了比位运算1的个数 + if isCmp(arr[i], arr[j]) { + tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } + } + } + return arr +} + +func isCmp(a, b int) bool { + bitA := bitCount(a) + bitB := bitCount(b) + if bitA == bitB { + return a > b + } else { + return bitA > bitB + } +} + +func bitCount(n int) int { + count := 0 + for n != 0 { + n &= (n-1) // 清除最低位的1 + count++ + } + return count +} ``` ## JavaScript diff --git a/problems/周总结/20201017二叉树周末总结.md b/problems/周总结/20201017二叉树周末总结.md index 57de82fd..f183924e 100644 --- a/problems/周总结/20201017二叉树周末总结.md +++ b/problems/周总结/20201017二叉树周末总结.md @@ -102,7 +102,7 @@ 现在已经讲过了几种二叉树了,二叉树,二叉平衡树,完全二叉树,二叉搜索树,后面还会有平衡二叉搜索树。 那么一些同学难免会有混乱了,我针对如下三个问题,帮大家在捋顺一遍: -1. 平衡二叉搜索数是不是二叉搜索树和平衡二叉树的结合? +1. 平衡二叉搜索树是不是二叉搜索树和平衡二叉树的结合? 是的,是二叉搜索树和平衡二叉树的结合。