diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index 48c6dd5d..c408fefc 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -130,10 +130,10 @@ class Solution: head_dummy.next = head slow, fast = head_dummy, head_dummy - while(n!=0): #fast先往前走n步 + while(n>=0): #fast先往前走n+1步 fast = fast.next n -= 1 - while(fast.next!=None): + while(fast!=None): slow = slow.next fast = fast.next #fast 走到结尾后,slow的下一个节点为倒数第N个节点 diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md index d9a656b9..b4dad9c3 100644 --- a/problems/0059.螺旋矩阵II.md +++ b/problems/0059.螺旋矩阵II.md @@ -117,6 +117,9 @@ public: }; ``` +* 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间 +* 空间复杂度 O(1) + ## 类似题目 * 54.螺旋矩阵 diff --git a/problems/0127.单词接龙.md b/problems/0127.单词接龙.md index 7ffd6a21..20ad5182 100644 --- a/problems/0127.单词接龙.md +++ b/problems/0127.单词接龙.md @@ -16,7 +16,7 @@ * 转换过程中的中间单词必须是字典 wordList 中的单词。 * 给你两个单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。 -  + 示例 1: * 输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] @@ -134,7 +134,70 @@ public int ladderLength(String beginWord, String endWord, List wordList) } ``` +```java +// Java 双向BFS +class Solution { + // 判断单词之间是否之差了一个字母 + public boolean isValid(String currentWord, String chooseWord) { + int count = 0; + for (int i = 0; i < currentWord.length(); i++) + if (currentWord.charAt(i) != chooseWord.charAt(i)) ++count; + return count == 1; + } + + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; // 如果 endWord 不在 wordList 中,那么无法成功转换,返回 0 + + // ansLeft 记录从 beginWord 开始 BFS 时能组成的单词数目 + // ansRight 记录从 endWord 开始 BFS 时能组成的单词数目 + int ansLeft = 0, ansRight = 0; + + // queueLeft 表示从 beginWord 开始 BFS 时使用的队列 + // queueRight 表示从 endWord 开始 BFS 时使用的队列 + Queue queueLeft = new ArrayDeque<>(), queueRight = new ArrayDeque<>(); + queueLeft.add(beginWord); + queueRight.add(endWord); + + // 从 beginWord 开始 BFS 时把遍历到的节点存入 hashSetLeft 中 + // 从 endWord 开始 BFS 时把遍历到的节点存入 hashSetRight 中 + Set hashSetLeft = new HashSet<>(), hashSetRight = new HashSet<>(); + hashSetLeft.add(beginWord); + hashSetRight.add(endWord); + + // 只要有一个队列为空,说明 beginWord 无法转换到 endWord + while (!queueLeft.isEmpty() && !queueRight.isEmpty()) { + ++ansLeft; + int size = queueLeft.size(); + for (int i = 0; i < size; i++) { + String currentWord = queueLeft.poll(); + // 只要 hashSetRight 中存在 currentWord,说明从 currentWord 可以转换到 endWord + if (hashSetRight.contains(currentWord)) return ansRight + ansLeft; + for (String chooseWord : wordList) { + if (hashSetLeft.contains(chooseWord) || !isValid(currentWord, chooseWord)) continue; + hashSetLeft.add(chooseWord); + queueLeft.add(chooseWord); + } + } + ++ansRight; + size = queueRight.size(); + for (int i = 0; i < size; i++) { + String currentWord = queueRight.poll(); + // 只要 hashSetLeft 中存在 currentWord,说明从 currentWord 可以转换到 beginWord + if (hashSetLeft.contains(currentWord)) return ansLeft + ansRight; + for (String chooseWord : wordList) { + if (hashSetRight.contains(chooseWord) || !isValid(currentWord, chooseWord)) continue; + hashSetRight.add(chooseWord); + queueRight.add(chooseWord); + } + } + } + return 0; + } +} +``` + ## Python + ``` class Solution: def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: @@ -301,3 +364,4 @@ function diffonechar(word1: string, word2: string): boolean { + diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index 0d25cba5..5e47ced8 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -143,9 +143,9 @@ class Solution { return resSet.stream().mapToInt(x -> x).toArray(); //方法2:另外申请一个数组存放setRes中的元素,最后返回数组 - int[] arr = new int[setRes.size()]; + int[] arr = new int[resSet.size()]; int j = 0; - for(int i : setRes){ + for(int i : resSet){ arr[j++] = i; } diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md index 5eb61ed0..925d7262 100644 --- a/problems/0376.摆动序列.md +++ b/problems/0376.摆动序列.md @@ -462,21 +462,43 @@ var wiggleMaxLength = function(nums) { ```Rust impl Solution { pub fn wiggle_max_length(nums: Vec) -> i32 { - let len = nums.len() as usize; - if len <= 1 { - return len as i32; + if nums.len() == 1 { + return 1; } - let mut preDiff = 0; - let mut curDiff = 0; - let mut result = 1; - for i in 0..len-1 { - curDiff = nums[i+1] - nums[i]; - if (preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0) { - result += 1; - preDiff = curDiff; + let mut res = 1; + let mut pre_diff = 0; + for i in 0..nums.len() - 1 { + let cur_diff = nums[i + 1] - nums[i]; + if (pre_diff <= 0 && cur_diff > 0) || (pre_diff >= 0 && cur_diff < 0) { + res += 1; + pre_diff = cur_diff; } } - result + res + } +} +``` + +**动态规划** + +```rust +impl Solution { + pub fn wiggle_max_length(nums: Vec) -> i32 { + if nums.len() == 1 { + return 1; + } + let (mut down, mut up) = (1, 1); + for i in 1..nums.len() { + // i - 1 为峰顶 + if nums[i] < nums[i - 1] { + down = down.max(up + 1); + } + // i - 1 为峰谷 + if nums[i] > nums[i - 1] { + up = up.max(down + 1); + } + } + down.max(up) } } ``` diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index 08d005f5..8726bf95 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -303,7 +303,7 @@ class Solution: target = sum(nums) if target % 2 == 1: return False target //= 2 - dp = [0] * (len(nums) + 1) + dp = [0] * (target + 1) for i in range(len(nums)): for j in range(target, nums[i] - 1, -1): dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]) diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md index 2437582c..63525b03 100644 --- a/problems/0455.分发饼干.md +++ b/problems/0455.分发饼干.md @@ -219,19 +219,17 @@ func findContentChildren(g []int, s []int) int { ### Rust ```rust -pub fn find_content_children(children: Vec, cookie: Vec) -> i32 { - let mut children = children; - let mut cookies = cookie; +pub fn find_content_children(mut children: Vec, mut cookie: Vec) -> i32 { children.sort(); cookies.sort(); - let (mut child, mut cookie) = (0usize, 0usize); + let (mut child, mut cookie) = (0, 0); while child < children.len() && cookie < cookies.len() { // 优先选择最小饼干喂饱孩子 if children[child] <= cookies[cookie] { child += 1; } - cookie += 1 + cookie += 1; } child as i32 } diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index 97b123bc..75135749 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -86,6 +86,9 @@ public: }; ``` +* 时间复杂度:O(log n) +* 空间复杂度:O(1) + ### 二分法第二种写法 @@ -125,6 +128,9 @@ public: } }; ``` +* 时间复杂度:O(log n) +* 空间复杂度:O(1) + ## 总结 diff --git a/problems/0827.最大人工岛.md b/problems/0827.最大人工岛.md index 1b49e9ee..45b2ef5a 100644 --- a/problems/0827.最大人工岛.md +++ b/problems/0827.最大人工岛.md @@ -219,7 +219,71 @@ public: }; ``` +# 其他语言版本 + +## Java + +```Java +class Solution { + private static final int[][] position = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 四个方向 + + /** + * @param grid 矩阵数组 + * @param row 当前遍历的节点的行号 + * @param col 当前遍历的节点的列号 + * @param mark 当前区域的标记 + * @return 返回当前区域内 1 的数量 + */ + public int dfs(int[][] grid, int row, int col, int mark) { + int ans = 0; + grid[row][col] = mark; + for (int[] current: position) { + int curRow = row + current[0], curCol = col + current[1]; + if (curRow < 0 || curRow >= grid.length || curCol < 0 || curCol >= grid.length) continue; // 越界 + if (grid[curRow][curCol] == 1) + ans += 1 + dfs(grid, curRow, curCol, mark); + } + return ans; + } + + public int largestIsland(int[][] grid) { + int ans = Integer.MIN_VALUE, size = grid.length, mark = 2; + Map getSize = new HashMap<>(); + for (int row = 0; row < size; row++) { + for (int col = 0; col < size; col++) { + if (grid[row][col] == 1) { + int areaSize = 1 + dfs(grid, row, col, mark); + getSize.put(mark++, areaSize); + } + } + } + for (int row = 0; row < size; row++) { + for (int col = 0; col < size; col++) { + // 当前位置如果不是 0 那么直接跳过,因为我们只能把 0 变成 1 + if (grid[row][col] != 0) continue; + Set hashSet = new HashSet<>(); // 防止同一个区域被重复计算 + // 计算从当前位置开始获取的 1 的数量,初始化 1 是因为把当前位置的 0 转换成了 1 + int curSize = 1; + for (int[] current: position) { + int curRow = row + current[0], curCol = col + current[1]; + if (curRow < 0 || curRow >= grid.length || curCol < 0 || curCol >= grid.length) continue; + int curMark = grid[curRow][curCol]; // 获取对应位置的标记 + // 如果标记存在 hashSet 中说明该标记被记录过一次,如果不存在 getSize 中说明该标记是无效标记(此时 curMark = 0) + if (hashSet.contains(curMark) || !getSize.containsKey(curMark)) continue; + hashSet.add(curMark); + curSize += getSize.get(curMark); + } + ans = Math.max(ans, curSize); + } + } + // 当 ans == Integer.MIN_VALUE 说明矩阵数组中不存在 0,全都是有效区域,返回数组大小即可 + return ans == Integer.MIN_VALUE ? size * size : ans; + } +} +``` +

+ diff --git a/problems/0841.钥匙和房间.md b/problems/0841.钥匙和房间.md index a973ab56..faf2b97f 100644 --- a/problems/0841.钥匙和房间.md +++ b/problems/0841.钥匙和房间.md @@ -275,6 +275,52 @@ class Solution { } ``` +```Java +// 广度优先搜索 +class Solution { + public boolean canVisitAllRooms(List> rooms) { + boolean[] visited = new boolean[rooms.size()]; // 用一个 visited 数据记录房间是否被访问 + visited[0] = true; + Queue queue = new ArrayDeque<>(); + queue.add(0); // 第 0 个房间标记为已访问 + while (!queue.isEmpty()) { + int curKey = queue.poll(); + for (int key: rooms.get(curKey)) { + if (visited[key]) continue; + visited[key] = true; + queue.add(key); + } + } + for (boolean key: visited) + if (!key) return false; + return true; + } +} +``` + +```java +// 广度优先遍历(时间优化) +class Solution { + public boolean canVisitAllRooms(List> rooms) { + int count = 1; // 用来记录可以被访问的房间数目,因为初始状态下 0 号房间可以被访问,所以置为 1 + boolean[] visited = new boolean[rooms.size()]; // 用一个 visited 数据记录房间是否被访问 + visited[0] = true; // 第 0 个房间标记为已访问 + Queue queue = new ArrayDeque<>(); + queue.add(0); + while (!queue.isEmpty()) { + int curKey = queue.poll(); + for (int key: rooms.get(curKey)) { + if (visited[key]) continue; + ++count; // 每访问一个访问房间就让 count 加 1 + visited[key] = true; + queue.add(key); + } + } + return count == rooms.size(); // 如果 count 等于房间数目,表示能进入所有房间,反之不能 + } +} +``` + ### python3 ```python diff --git a/problems/前序/ACM模式如何构建二叉树.md b/problems/前序/ACM模式如何构建二叉树.md index 42bf7af0..b6446403 100644 --- a/problems/前序/ACM模式如何构建二叉树.md +++ b/problems/前序/ACM模式如何构建二叉树.md @@ -305,11 +305,12 @@ def construct_binary_tree(nums: []) -> TreeNode: Tree.append(node) if i == 0: root = node + # 直接判断2*i+2) -> Vec> { + let mut res = vec![]; + let mut path = vec![]; + nums.sort(); + Self::backtracking(&nums, &mut path, &mut res, 0); + res + } + pub fn backtracking( + nums: &Vec, + path: &mut Vec, + res: &mut Vec>, + start_index: usize, + ) { + res.push(path.clone()); + let mut helper_set = HashSet::new(); + for i in start_index..nums.len() { + if helper_set.contains(&nums[i]) { + continue; + } + helper_set.insert(nums[i]); + path.push(nums[i]); + Self::backtracking(nums, path, res, i + 1); + path.pop(); + } + } +} +``` + +**40. 组合总和 II** + +```rust +use std::collections::HashSet; +impl Solution { + pub fn backtracking( + candidates: &Vec, + target: i32, + sum: i32, + path: &mut Vec, + res: &mut Vec>, + start_index: usize, + ) { + if sum > target { + return; + } + if sum == target { + res.push(path.clone()); + } + let mut helper_set = HashSet::new(); + for i in start_index..candidates.len() { + if sum + candidates[i] <= target { + if helper_set.contains(&candidates[i]) { + continue; + } + helper_set.insert(candidates[i]); + path.push(candidates[i]); + Self::backtracking(candidates, target, sum + candidates[i], path, res, i + 1); + path.pop(); + } + } + } + + pub fn combination_sum2(mut candidates: Vec, target: i32) -> Vec> { + let mut res = vec![]; + let mut path = vec![]; + candidates.sort(); + Self::backtracking(&candidates, target, 0, &mut path, &mut res, 0); + res + } +} +``` + +**47. 全排列 II** + +```rust +use std::collections::HashSet; +impl Solution { + pub fn permute_unique(mut nums: Vec) -> Vec> { + let mut res = vec![]; + let mut path = vec![]; + let mut used = vec![false; nums.len()]; + Self::backtracking(&mut res, &mut path, &nums, &mut used); + res + } + pub fn backtracking( + res: &mut Vec>, + path: &mut Vec, + nums: &Vec, + used: &mut Vec, + ) { + if path.len() == nums.len() { + res.push(path.clone()); + return; + } + let mut helper_set = HashSet::new(); + for i in 0..nums.len() { + if used[i] || helper_set.contains(&nums[i]) { + continue; + } + helper_set.insert(nums[i]); + path.push(nums[i]); + used[i] = true; + Self::backtracking(res, path, nums, used); + used[i] = false; + path.pop(); + } + } +} +```