diff --git a/README.md b/README.md index df397457..276c8313 100644 --- a/README.md +++ b/README.md @@ -116,10 +116,11 @@ 1. [关于链表,你该了解这些!](./problems/链表理论基础.md) 2. [链表:听说用虚拟头节点会方便很多?](./problems/0203.移除链表元素.md) 3. [链表:一道题目考察了常见的五个操作!](./problems/0707.设计链表.md) -4. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) -5. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) -5. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) -6. [链表:总结篇!](./problems/链表总结篇.md) +4. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) +5. [链表:两两交换链表中的节点](./problems/0024.两两交换链表中的节点.md) +6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) +7. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) +8. [链表:总结篇!](./problems/链表总结篇.md) ## 哈希表 diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md index 6f51a181..f06ed80a 100644 --- a/problems/0017.电话号码的字母组合.md +++ b/problems/0017.电话号码的字母组合.md @@ -240,7 +240,46 @@ public: Java: +```Java +class Solution { + //设置全局列表存储最后的结果 + List list = new ArrayList<>(); + + public List letterCombinations(String digits) { + if (digits == null || digits.length() == 0) { + return list; + } + //初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串"" + String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; + //迭代处理 + backTracking(digits, numString, 0); + return list; + + } + + //每次迭代获取一个字符串,所以会设计大量的字符串拼接,所以这里选择更为高效的 StringBuild + StringBuilder temp = new StringBuilder(); + + //比如digits如果为"23",num 为0,则str表示2对应的 abc + public void backTracking(String digits, String[] numString, int num) { + //遍历全部一次记录一次得到的字符串 + if (num == digits.length()) { + list.add(temp.toString()); + return; + } + //str 表示当前num对应的字符串 + String str = numString[digits.charAt(num) - '0']; + for (int i = 0; i < str.length(); i++) { + temp.append(str.charAt(i)); + //回溯 + backTracking(digits, numString, num + 1); + //剔除末尾的继续尝试 + temp.deleteCharAt(temp.length() - 1); + } + } +} +``` Python: diff --git a/problems/0020.有效的括号.md b/problems/0020.有效的括号.md index f2d78ade..4dae7072 100644 --- a/problems/0020.有效的括号.md +++ b/problems/0020.有效的括号.md @@ -138,7 +138,31 @@ public: Java: - +```Java +class Solution { + public boolean isValid(String s) { + Deque deque = new LinkedList<>(); + char ch; + for (int i = 0; i < s.length(); i++) { + ch = s.charAt(i); + //碰到左括号,就把相应的右括号入栈 + if (ch == '(') { + deque.push(')'); + }else if (ch == '{') { + deque.push('}'); + }else if (ch == '[') { + deque.push(']'); + } else if (deque.isEmpty() || deque.peek() != ch) { + return false; + }else {//如果是右括号判断是否和栈顶元素匹配 + deque.pop(); + } + } + //最后判断栈中元素是否匹配 + return deque.isEmpty(); + } +} +``` Python: ```python3 diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md new file mode 100644 index 00000000..9f07b4f7 --- /dev/null +++ b/problems/0024.两两交换链表中的节点.md @@ -0,0 +1,100 @@ + +

+ + + + +

+

欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ +## 24. 两两交换链表中的节点 + +给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 + +你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + + +24.两两交换链表中的节点-题意 + +## 思路 + +这道题目正常模拟就可以了。 + +建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。 + +对虚拟头结点的操作,还不熟悉的话,可以看这篇[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)。 + +接下来就是交换相邻两个元素了,**此时一定要画图,不画图,操作多个指针很容易乱,而且要操作的先后顺序** + +初始时,cur指向虚拟头结点,然后进行如下三步: + +![24.两两交换链表中的节点1](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B91.png) + +操作之后,链表如下: + +![24.两两交换链表中的节点2](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B92.png) + +看这个可能就更直观一些了: + + +![24.两两交换链表中的节点3](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B93.png) + +对应的C++代码实现如下: (注释中详细和如上图中的三步做对应) + +```C++ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点 + dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作 + ListNode* cur = dummyHead; + while(cur->next != nullptr && cur->next->next != nullptr) { + ListNode* tmp = cur->next; // 记录临时节点 + ListNode* tmp1 = cur->next->next->next; // 记录临时节点 + + cur->next = cur->next->next; // 步骤一 + cur->next->next = tmp; // 步骤二 + cur->next->next->next = tmp1; // 步骤三 + + cur = cur->next->next; // cur移动两位,准备下一轮交换 + } + return dummyHead->next; + } +}; +``` +* 时间复杂度:$O(n)$ +* 空间复杂度:$O(1)$ + +## 拓展 + +**这里还是说一下,大家不必太在意力扣上执行用时,打败多少多少用户,这个统计不准确的。** + +做题的时候自己能分析出来时间复杂度就可以了,至于力扣上执行用时,大概看一下就行。 + +上面的代码我第一次提交执行用时8ms,打败6.5%的用户,差点吓到我了。 + +心想应该没有更好的方法了吧,也就O(n)的时间复杂度,重复提交几次,这样了: + +![24.两两交换链表中的节点](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.png) + +力扣上的统计如果两份代码是 100ms 和 300ms的耗时,其实是需要注意的。 + +如果一个是 4ms 一个是 12ms,看上去好像是一个打败了80%,一个打败了20%,其实是没有差别的。 只不过是力扣上统计的误差而已。 + + +## 其他语言版本 + + +Java: + + +Python: + +Go: + + +----------------------- +* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) +* B站视频:[代码随想录](https://space.bilibili.com/525438321) +* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) +
diff --git a/problems/0037.解数独.md b/problems/0037.解数独.md index 75e2d3cd..7b59fad9 100644 --- a/problems/0037.解数独.md +++ b/problems/0037.解数独.md @@ -219,7 +219,72 @@ public: Java: +```java +class Solution { + public void solveSudoku(char[][] board) { + solveSudokuHelper(board); + } + private boolean solveSudokuHelper(char[][] board){ + //「一个for循环遍历棋盘的行,一个for循环遍历棋盘的列, + // 一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!」 + for (int i = 0; i < 9; i++){ // 遍历行 + for (int j = 0; j < 9; j++){ // 遍历列 + if (board[i][j] != '.'){ // 跳过原始数字 + continue; + } + for (char k = '1'; k <= '9'; k++){ // (i, j) 这个位置放k是否合适 + if (isValidSudoku(i, j, k, board)){ + board[i][j] = k; + if (solveSudokuHelper(board)){ // 如果找到合适一组立刻返回 + return true; + } + board[i][j] = '.'; + } + } + // 9个数都试完了,都不行,那么就返回false + return false; + // 因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解! + // 那么会直接返回, 「这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去!」 + } + } + // 遍历完没有返回false,说明找到了合适棋盘位置了 + return true; + } + + /** + * 判断棋盘是否合法有如下三个维度: + * 同行是否重复 + * 同列是否重复 + * 9宫格里是否重复 + */ + private boolean isValidSudoku(int row, int col, char val, char[][] board){ + // 同行是否重复 + for (int i = 0; i < 9; i++){ + if (board[row][i] == val){ + return false; + } + } + // 同列是否重复 + for (int j = 0; j < 9; j++){ + if (board[j][col] == val){ + return false; + } + } + // 9宫格里是否重复 + int startRow = (row / 3) * 3; + int startCol = (col / 3) * 3; + for (int i = startRow; i < startRow + 3; i++){ + for (int j = startCol; j < startCol + 3; j++){ + if (board[i][j] == val){ + return false; + } + } + } + return true; + } +} +``` Python: diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md index f983a994..ab118ee0 100644 --- a/problems/0039.组合总和.md +++ b/problems/0039.组合总和.md @@ -236,7 +236,39 @@ public: Java: +```Java +class Solution { + List> lists = new ArrayList<>(); + Deque deque = new LinkedList<>(); + public List> combinationSum3(int k, int n) { + int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + backTracking(arr, n, k, 0); + return lists; + } + + public void backTracking(int[] arr, int n, int k, int startIndex) { + //如果 n 小于0,没必要继续本次递归,已经不符合要求了 + if (n < 0) { + return; + } + if (deque.size() == k) { + if (n == 0) { + lists.add(new ArrayList(deque)); + } + return; + } + for (int i = startIndex; i < arr.length - (k - deque.size()) + 1; i++) { + deque.push(arr[i]); + //减去当前元素 + n -= arr[i]; + backTracking(arr, n, k, i + 1); + //恢复n + n += deque.pop(); + } + } +} +``` Python: diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index ffcbe212..50898016 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -255,7 +255,43 @@ public: Java: +```Java +class Solution { + List> lists = new ArrayList<>(); + Deque deque = new LinkedList<>(); + 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 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; + } + } +} +``` Python: diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md index 2def83a9..b8e369e6 100644 --- a/problems/0045.跳跃游戏II.md +++ b/problems/0045.跳跃游戏II.md @@ -143,7 +143,36 @@ public: Java: - +```Java +class Solution { + public int jump(int[] nums) { + if (nums == null || nums.length == 0 || nums.length == 1) { + return 0; + } + //记录跳跃的次数 + int count=0; + //当前的覆盖最大区域 + int curDistance = 0; + //最大的覆盖区域 + int maxDistance = 0; + for (int i = 0; i < nums.length; i++) { + //在可覆盖区域内更新最大的覆盖区域 + maxDistance = Math.max(maxDistance,i+nums[i]); + //说明当前一步,再跳一步就到达了末尾 + if (maxDistance>=nums.length-1){ + count++; + break; + } + //走到当前覆盖的最大区域时,更新下一步可达的最大区域 + if (i==curDistance){ + curDistance = maxDistance; + count++; + } + } + return count; + } +} +``` Python: diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md index 5f7b1ac0..05d86785 100644 --- a/problems/0046.全排列.md +++ b/problems/0046.全排列.md @@ -147,7 +147,41 @@ public: Java: +```java +class Solution { + List> result = new ArrayList<>();// 存放符合条件结果的集合 + LinkedList path = new LinkedList<>();// 用来存放符合条件结果 + boolean[] used; + public List> permute(int[] nums) { + if (nums.length == 0){ + return result; + } + used = new boolean[nums.length]; + permuteHelper(nums); + return result; + } + private void permuteHelper(int[] nums){ + if (path.size() == nums.length){ + result.add(new ArrayList<>(path)); + return; + } + for (int i = 0; i < nums.length; i++){ + // if (path.contains(nums[i])){ + // continue; + // } + if (used[i]){ + continue; + } + used[i] = true; + path.add(nums[i]); + permuteHelper(nums); + path.removeLast(); + used[i] = false; + } + } +} +``` Python: diff --git a/problems/0053.最大子序和.md b/problems/0053.最大子序和.md index b8a9d748..436e763b 100644 --- a/problems/0053.最大子序和.md +++ b/problems/0053.最大子序和.md @@ -139,10 +139,40 @@ public: Java: - +```java +class Solution { + public int maxSubArray(int[] nums) { + if (nums.length == 1){ + return nums[0]; + } + int sum = Integer.MIN_VALUE; + int count = 0; + for (int i = 0; i < nums.length; i++){ + count += nums[i]; + sum = Math.max(sum, count); // 取区间累计的最大值(相当于不断确定最大子序终止位置) + if (count <= 0){ + count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和 + } + } + return sum; + } +} +``` Python: - +```python +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + result = -float('inf') + count = 0 + for i in range(len(nums)): + count += nums[i] + if count > result: + result = count + if count <= 0: + count = 0 + return result +``` Go: diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md index 0cad1fa7..179ac246 100644 --- a/problems/0055.跳跃游戏.md +++ b/problems/0055.跳跃游戏.md @@ -86,7 +86,25 @@ public: Java: - +```Java +class Solution { + public boolean canJump(int[] nums) { + if (nums.length == 1) { + return true; + } + //覆盖范围 + int coverRange = nums[0]; + //在覆盖范围内更新最大的覆盖范围 + for (int i = 0; i <= coverRange; i++) { + coverRange = Math.max(coverRange, i + nums[i]); + if (coverRange >= nums.length - 1) { + return true; + } + } + return false; + } +} +``` Python: diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 3dfb5216..f31766e0 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -340,6 +340,33 @@ public: Java: +```java +class Solution { + List> result = new ArrayList<>(); + LinkedList path = new LinkedList<>(); + public List> combine(int n, int k) { + combineHelper(n, k, 1); + return result; + } + + /** + * 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex + * @param startIndex 用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。 + */ + private void combineHelper(int n, int k, int startIndex){ + //终止条件 + if (path.size() == k){ + result.add(new ArrayList<>(path)); + return; + } + for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){ + path.add(i); + combineHelper(n, k, i + 1); + path.removeLast(); + } + } +} +``` Python: diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md index 2af123d1..a8a17858 100644 --- a/problems/0077.组合优化.md +++ b/problems/0077.组合优化.md @@ -147,7 +147,33 @@ public: Java: +``` +class Solution { + List> result = new ArrayList<>(); + LinkedList path = new LinkedList<>(); + public List> combine(int n, int k) { + combineHelper(n, k, 1); + return result; + } + /** + * 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex + * @param startIndex 用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。 + */ + private void combineHelper(int n, int k, int startIndex){ + //终止条件 + if (path.size() == k){ + result.add(new ArrayList<>(path)); + return; + } + for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){ + path.add(i); + combineHelper(n, k, i + 1); + path.removeLast(); + } + } +} +``` Python: diff --git a/problems/0078.子集.md b/problems/0078.子集.md index 139d0ed5..7166f7fa 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -177,7 +177,33 @@ public: Java: +```java +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; + } + Arrays.sort(nums); + subsetsHelper(nums, 0); + return result; + } + private void subsetsHelper(int[] nums, int startIndex){ + result.add(new ArrayList<>(path));//「遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合」。 + if (startIndex >= nums.length){ //终止条件可不加 + return; + } + for (int i = startIndex; i < nums.length; i++){ + path.add(nums[i]); + subsetsHelper(nums, i + 1); + path.removeLast(); + } + } +} +``` Python: @@ -206,6 +232,24 @@ func Dfs(temp, nums []int, start int){ } ``` +Javascript: + +```Javascript +var subsets = function(nums) { + let result = [] + let path = [] + function backtracking(startIndex) { + result.push(path.slice()) + for(let i = startIndex; i < nums.length; i++) { + path.push(nums[i]) + backtracking(i + 1) + path.pop() + } + } + backtracking(0) + return result +}; +``` ----------------------- diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index cc5fd571..47db79f7 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -172,7 +172,40 @@ if (i > startIndex && nums[i] == nums[i - 1] ) { Java: - +```java +class Solution { + List> result = new ArrayList<>();// 存放符合条件结果的集合 + LinkedList path = new LinkedList<>();// 用来存放符合条件结果 + boolean[] used; + public List> subsetsWithDup(int[] nums) { + if (nums.length == 0){ + result.add(path); + return result; + } + Arrays.sort(nums); + used = new boolean[nums.length]; + subsetsWithDupHelper(nums, 0); + return result; + } + + private void subsetsWithDupHelper(int[] nums, int startIndex){ + result.add(new ArrayList<>(path)); + if (startIndex >= nums.length){ + return; + } + for (int i = startIndex; i < nums.length; i++){ + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]){ + continue; + } + path.add(nums[i]); + used[i] = true; + subsetsWithDupHelper(nums, i + 1); + path.removeLast(); + used[i] = false; + } + } +} +``` Python: diff --git a/problems/0096.不同的二叉搜索树.md b/problems/0096.不同的二叉搜索树.md index 2764277c..7dea8fb0 100644 --- a/problems/0096.不同的二叉搜索树.md +++ b/problems/0096.不同的二叉搜索树.md @@ -165,7 +165,25 @@ public: Java: - +```Java +class Solution { + public int numTrees(int n) { + //初始化 dp 数组 + int[] dp = new int[n + 1]; + //初始化0个节点和1个节点的情况 + dp[0] = 1; + dp[1] = 1; + for (int i = 2; i <= n; i++) { + for (int j = 1; j <= i; j++) { + //对于第i个节点,需要考虑1作为根节点直到i作为根节点的情况,所以需要累加 + //一共i个节点,对于根节点j时,左子树的节点个数为j-1,右子树的节点个数为i-j + dp[i] += dp[j - 1] * dp[i - j]; + } + } + return dp[n]; + } +} +``` Python: diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index be2e9dca..0781e01d 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -419,18 +419,17 @@ public: Java: -``` Java - - +```Java class Solution { public List> resList=new ArrayList>(); public List> levelOrder(TreeNode root) { - checkFun01(root,0); - + //checkFun01(root,0); + checkFun02(root); + return resList; } - //递归方式 + //DFS--递归方式 public void checkFun01(TreeNode node,Integer deep){ if(node==null) return; deep++; @@ -442,12 +441,33 @@ class Solution { } resList.get(deep-1).add(node.val); - checkFun01(node.left,deep); checkFun01(node.right,deep); } + + //BFS--迭代方式--借助队列 + public void checkFun02(TreeNode node){ + if(node==null) return; + Queue que=new LinkedList(); + que.offer(node); + while(!que.isEmpty()){ + List itemList=new ArrayList(); + int len=que.size(); + while(len>0){ + TreeNode tmpNode=que.poll(); + itemList.add(tmpNode.val); + + if(tmpNode.left!=null) que.offer(tmpNode.left); + if(tmpNode.right!=null) que.offer(tmpNode.right); + len--; + } + + resList.add(itemList); + } + + } ``` @@ -458,7 +478,6 @@ Go: - ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md index 430cd5d6..6c6b4632 100644 --- a/problems/0111.二叉树的最小深度.md +++ b/problems/0111.二叉树的最小深度.md @@ -195,9 +195,51 @@ public: Java: - Python: +递归法: + +```python +class Solution: + def minDepth(self, root: TreeNode) -> int: + if not root: + return 0 + if not root.left and not root.right: + return 1 + + min_depth = 10**9 + if root.left: + min_depth = min(self.minDepth(root.left), min_depth) # 获得左子树的最小高度 + if root.right: + min_depth = min(self.minDepth(root.right), min_depth) # 获得右子树的最小高度 + return min_depth + 1 +``` + +迭代法: + +```python +class Solution: + def minDepth(self, root: TreeNode) -> int: + if not root: + return 0 + que = deque() + que.append(root) + res = 1 + + while que: + for _ in range(len(que)): + node = que.popleft() + # 当左右孩子都为空的时候,说明是最低点的一层了,退出 + if not node.left and not node.right: + return res + if node.left is not None: + que.append(node.left) + if node.right is not None: + que.append(node.right) + res += 1 + return res +``` + Go: @@ -208,4 +250,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 01ff35c5..9c86a3bc 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -250,7 +250,46 @@ public: Java: +```Java +class Solution { + List> lists = new ArrayList<>(); + Deque deque = new LinkedList<>(); + public List> partition(String s) { + backTracking(s, 0); + return lists; + } + + private void backTracking(String s, int startIndex) { + //如果起始位置大于s的大小,说明找到了一组分割方案 + if (startIndex >= s.length()) { + lists.add(new ArrayList(deque)); + return; + } + for (int i = startIndex; i < s.length(); i++) { + //如果是回文子串,则记录 + if (isPalindrome(s, startIndex, i)) { + String str = s.substring(startIndex, i + 1); + deque.addLast(str); + } else { + continue; + } + //起始位置后移,保证不重复 + backTracking(s, i + 1); + deque.removeLast(); + } + } + //判断是否是回文串 + private boolean isPalindrome(String s, int startIndex, int end) { + for (int i = startIndex, j = end; i < j; i++, j--) { + if (s.charAt(i) != s.charAt(j)) { + return false; + } + } + return true; + } +} +``` Python: diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index e6667091..9fca1ee0 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -138,7 +138,63 @@ public: Java: - +```java +/** + * 添加虚节点方式 + * 时间复杂度 O(n) + * 空间复杂度 O(1) + * @param head + * @param val + * @return + */ +public ListNode removeElements(ListNode head, int val) { + if (head == null) { + return head; + } + // 因为删除可能涉及到头节点,所以设置dummy节点,统一操作 + ListNode dummy = new ListNode(-1, head); + ListNode pre = dummy; + ListNode cur = head; + while (cur != null) { + if (cur.val == val) { + pre.next = cur.next; + } else { + pre = cur; + } + cur = cur.next; + } + return dummy.next; +} +/** + * 不添加虚拟节点方式 + * 时间复杂度 O(n) + * 空间复杂度 O(1) + * @param head + * @param val + * @return + */ +public ListNode removeElements(ListNode head, int val) { + while (head != null && head.val == val) { + head = head.next; + } + // 已经为null,提前退出 + if (head == null) { + return head; + } + // 已确定当前head.val != val + ListNode pre = head; + ListNode cur = head.next; + while (cur != null) { + if (cur.val == val) { + pre.next = cur.next; + } else { + pre = cur; + } + cur = cur.next; + } + return head; +} +``` Python: diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md index 49b5c62b..4018364a 100644 --- a/problems/0225.用队列实现栈.md +++ b/problems/0225.用队列实现栈.md @@ -154,9 +154,58 @@ public: ## 其他语言版本 - Java: +```java +class MyStack { + + Queue queue1; // 和栈中保持一样元素的队列 + Queue queue2; // 辅助队列 + + /** Initialize your data structure here. */ + public MyStack() { + queue1 = new LinkedList<>(); + queue2 = new LinkedList<>(); + } + + /** Push element x onto stack. */ + public void push(int x) { + queue2.offer(x); // 先放在辅助队列中 + while (!queue1.isEmpty()){ + queue2.offer(queue1.poll()); + } + Queue queueTemp; + queueTemp = queue1; + queue1 = queue2; + queue2 = queueTemp; // 最后交换queue1和queue2,将元素都放到queue1中 + } + + /** Removes the element on top of the stack and returns that element. */ + public int pop() { + return queue1.poll(); // 因为queue1中的元素和栈中的保持一致,所以这个和下面两个的操作只看queue1即可 + } + + /** Get the top element. */ + public int top() { + return queue1.peek(); + } + + /** Returns whether the stack is empty. */ + public boolean empty() { + return queue1.isEmpty(); + } +} + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue obj = new MyQueue(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.peek(); + * boolean param_4 = obj.empty(); + */ +``` + Python: @@ -227,4 +276,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index 9907b476..abdc363d 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -19,7 +19,7 @@ push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 返回队列是否为空。 -  + 示例: @@ -129,9 +129,62 @@ public: ## 其他语言版本 - Java: +```java +class MyQueue { + + Stack stack1; + Stack stack2; + + /** Initialize your data structure here. */ + public MyQueue() { + stack1 = new Stack<>(); // 负责进栈 + stack2 = new Stack<>(); // 负责出栈 + } + + /** Push element x to the back of queue. */ + public void push(int x) { + stack1.push(x); + } + + /** Removes the element from in front of queue and returns that element. */ + public int pop() { + dumpStack1(); + return stack2.pop(); + } + + /** Get the front element. */ + public int peek() { + dumpStack1(); + return stack2.peek(); + } + + /** Returns whether the queue is empty. */ + public boolean empty() { + return stack1.isEmpty() && stack2.isEmpty(); + } + + // 如果stack2为空,那么将stack1中的元素全部放到stack2中 + private void dumpStack1(){ + if (stack2.isEmpty()){ + while (!stack1.isEmpty()){ + stack2.push(stack1.pop()); + } + } + } +} + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue obj = new MyQueue(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.peek(); + * boolean param_4 = obj.empty(); + */ +``` + Python: @@ -145,4 +198,4 @@ Go: * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) -
+
\ No newline at end of file diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md index 709fa09e..781bfa6f 100644 --- a/problems/0239.滑动窗口最大值.md +++ b/problems/0239.滑动窗口最大值.md @@ -207,7 +207,60 @@ public: Java: +```Java +//自定义数组 +class MyQueue { + Deque deque = new LinkedList<>(); + //弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出 + //同时判断队列当前是否为空 + void poll(int val) { + if (!deque.isEmpty() && val == deque.peek()) { + deque.poll(); + } + } + //添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出 + //保证队列元素单调递减 + //比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2 + void add(int val) { + while (!deque.isEmpty() && val > deque.getLast()) { + deque.removeLast(); + } + deque.add(val); + } + //队列队顶元素始终为最大值 + int peek() { + return deque.peek(); + } +} +class Solution { + public int[] maxSlidingWindow(int[] nums, int k) { + if (nums.length == 1) { + return nums; + } + int len = nums.length - k + 1; + //存放结果元素的数组 + int[] res = new int[len]; + int num = 0; + //自定义队列 + MyQueue myQueue = new MyQueue(); + //先将前k的元素放入队列 + for (int i = 0; i < k; i++) { + myQueue.add(nums[i]); + } + res[num++] = myQueue.peek(); + for (int i = k; i < nums.length; i++) { + //滑动窗口移除最前面的元素,移除是判断该元素是否放入队列 + myQueue.poll(nums[i - k]); + //滑动窗口加入最后面的元素 + myQueue.add(nums[i]); + //记录对应的最大值 + res[num++] = myQueue.peek(); + } + return res; + } +} +``` Python: diff --git a/problems/0279.完全平方数.md b/problems/0279.完全平方数.md index 39260926..d72e9099 100644 --- a/problems/0279.完全平方数.md +++ b/problems/0279.完全平方数.md @@ -159,7 +159,28 @@ public: Java: - +```Java +class Solution { + public int numSquares(int n) { + int max = Integer.MAX_VALUE; + int[] dp = new int[n + 1]; + //初始化 + for (int j = 0; j <= n; j++) { + dp[j] = max; + } + //当和为0时,组合的个数为0 + dp[0] = 0; + for (int i = 1; i * i <= n; i++) { + for (int j = i * i; j <= n; j++) { + if (dp[j - i * i] != max) { + dp[j] = Math.min(dp[j], dp[j - i * i] + 1); + } + } + } + return dp[n]; + } +} +``` Python: diff --git a/problems/0322.零钱兑换.md b/problems/0322.零钱兑换.md index fbb9c6df..e67695d8 100644 --- a/problems/0322.零钱兑换.md +++ b/problems/0322.零钱兑换.md @@ -181,7 +181,31 @@ public: Java: - +```Java +class Solution { + public int coinChange(int[] coins, int amount) { + int max = Integer.MAX_VALUE; + int[] dp = new int[amount + 1]; + //初始化dp数组为最大值 + for (int j = 0; j < dp.length; j++) { + dp[j] = max; + } + //当金额为0时需要的硬币数目为0 + dp[0] = 0; + for (int i = 0; i < coins.length; i++) { + //正序遍历:完全背包每个硬币可以选择多次 + for (int j = coins[i]; j <= amount; j++) { + //只有dp[j-coins[i]]不是初始最大值时,该位才有选择的必要 + if (dp[j - coins[i]] != max) { + //选择硬币数目最小的情况 + dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1); + } + } + } + return dp[amount] == max ? -1 : dp[amount]; + } +} +``` Python: diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md index c2f16794..b4c843b7 100644 --- a/problems/0344.反转字符串.md +++ b/problems/0344.反转字符串.md @@ -140,7 +140,21 @@ public: Java: - +```Java +class Solution { + public void reverseString(char[] s) { + int l = 0; + int r = s.length - 1; + while (l < r) { + s[l] ^= s[r]; //构造 a ^ b 的结果,并放在 a 中 + s[r] ^= s[l]; //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b + s[l] ^= s[r]; //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换 + l++; + r--; + } + } +} +``` Python: diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index c196b467..75ef9061 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -75,7 +75,37 @@ public: Java: +```Java +import java.util.HashSet; +import java.util.Set; +class Solution { + public int[] intersection(int[] nums1, int[] nums2) { + if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) { + return new int[0]; + } + Set set1 = new HashSet<>(); + Set resSet = new HashSet<>(); + //遍历数组1 + for (int i : nums1) { + set1.add(i); + } + //遍历数组2的过程中判断哈希表中是否存在该元素 + for (int i : nums2) { + if (set1.contains(i)) { + resSet.add(i); + } + } + int[] resArr = new int[resSet.size()]; + int index = 0; + //将结果几何转为数组 + for (int i : resSet) { + resArr[index++] = i; + } + return resArr; + } +} +``` Python: diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md index 6ae76526..fa90142d 100644 --- a/problems/0376.摆动序列.md +++ b/problems/0376.摆动序列.md @@ -111,7 +111,31 @@ public: Java: - +```Java +class Solution { + public int wiggleMaxLength(int[] nums) { + if (nums == null || nums.length <= 1) { + return nums.length; + } + //当前差值 + int curDiff = 0; + //上一个差值 + int preDiff = 0; + int count = 1; + for (int i = 1; i < nums.length; i++) { + //得到当前差值 + curDiff = nums[i] - nums[i - 1]; + //如果当前差值和上一个差值为一正一负 + //等于0的情况表示初始时的preDiff + if ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) { + count++; + preDiff = curDiff; + } + } + return count; + } +} +``` Python: diff --git a/problems/0377.组合总和Ⅳ.md b/problems/0377.组合总和Ⅳ.md index b0b83718..8f8cfd86 100644 --- a/problems/0377.组合总和Ⅳ.md +++ b/problems/0377.组合总和Ⅳ.md @@ -147,7 +147,23 @@ C++测试用例有超过两个树相加超过int的数据,所以需要在if里 Java: +```Java +class Solution { + public int combinationSum4(int[] nums, int target) { + int[] dp = new int[target + 1]; + dp[0] = 1; + for (int i = 0; i <= target; i++) { + for (int j = 0; j < nums.length; j++) { + if (i >= nums[j]) { + dp[i] += dp[i - nums[j]]; + } + } + } + return dp[target]; + } +} +``` Python: diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index ca9b6061..742bfdc3 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -111,7 +111,31 @@ public: Java: +```Java +class Solution { + public boolean canConstruct(String ransomNote, String magazine) { + //记录杂志字符串出现的次数 + int[] arr = new int[26]; + int temp; + for (int i = 0; i < magazine.length(); i++) { + temp = magazine.charAt(i) - 'a'; + arr[temp]++; + } + for (int i = 0; i < ransomNote.length(); i++) { + temp = ransomNote.charAt(i) - 'a'; + //对于金信中的每一个字符都在数组中查找 + //找到相应位减一,否则找不到返回false + if (arr[temp] > 0) { + arr[temp]--; + } else { + return false; + } + } + return true; + } +} +``` Python: diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index 257c4d7d..789a7fb5 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -185,7 +185,41 @@ public: Java: +```Java +class Solution { + public boolean canPartition(int[] nums) { + int sum = 0; + for (int i : nums) { + sum += i; + } + if ((sum & 1) == 1) { + return false; + } + int length = nums.length; + int target = sum >> 1; + //dp[j]表示前i个元素可以找到相加等于j情况 + boolean[] dp = new boolean[target + 1]; + //对于第一个元素,只有当j=nums[0]时,才恰好填充满 + if (nums[0] <= target) { + dp[nums[0]] = true; + } + for (int i = 1; i < length; i++) { + //j由右往左直到nums[i] + for (int j = target; j >= nums[i]; j--) { + //只有两种情况,要么放,要么不放 + //取其中的TRUE值 + dp[j] = dp[j] || dp[j - nums[i]]; + } + //一旦满足,结束,因为只需要找到一组值即可 + if (dp[target]) { + return dp[target]; + } + } + return dp[target]; + } +} +``` Python: diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index 71dcc1ae..a2ef928b 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -88,7 +88,36 @@ public: Java: - +```Java +class Solution { + public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { + Map map = new HashMap<>(); + int temp; + int res = 0; + //统计两个数组中的元素之和,同时统计出现的次数,放入map + for (int i : nums1) { + for (int j : nums2) { + temp = i + j; + if (map.containsKey(temp)) { + map.put(temp, map.get(temp) + 1); + } else { + map.put(temp, 1); + } + } + } + //统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数 + for (int i : nums3) { + for (int j : nums4) { + temp = i + j; + if (map.containsKey(0 - temp)) { + res += map.get(0 - temp); + } + } + } + return res; + } +} +``` Python: diff --git a/problems/0474.一和零.md b/problems/0474.一和零.md index 7970c38e..4ec5fd4d 100644 --- a/problems/0474.一和零.md +++ b/problems/0474.一和零.md @@ -161,7 +161,33 @@ public: Java: - +```Java +class Solution { + public int findMaxForm(String[] strs, int m, int n) { + //dp[i][j]表示i个0和j个1时的最大子集 + int[][] dp = new int[m + 1][n + 1]; + int oneNum, zeroNum; + for (String str : strs) { + oneNum = 0; + zeroNum = 0; + for (char ch : str.toCharArray()) { + if (ch == '0') { + zeroNum++; + } else { + oneNum++; + } + } + //倒序遍历 + for (int i = m; i >= zeroNum; i--) { + for (int j = n; j >= oneNum; j--) { + dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1); + } + } + } + return dp[m][n]; + } +} +``` Python: diff --git a/problems/0518.零钱兑换II.md b/problems/0518.零钱兑换II.md index 46e52cc0..15c9d7d0 100644 --- a/problems/0518.零钱兑换II.md +++ b/problems/0518.零钱兑换II.md @@ -188,7 +188,22 @@ public: Java: - +```Java +class Solution { + public int change(int amount, int[] coins) { + //递推表达式 + int[] dp = new int[amount + 1]; + //初始化dp数组,表示金额为0时只有一种情况,也就是什么都不装 + dp[0] = 1; + for (int i = 0; i < coins.length; i++) { + for (int j = coins[i]; j <= amount; j++) { + dp[j] += dp[j - coins[i]]; + } + } + return dp[amount]; + } +} +``` Python: diff --git a/problems/0541.反转字符串II.md b/problems/0541.反转字符串II.md index 6a84006e..0a92ac8b 100644 --- a/problems/0541.反转字符串II.md +++ b/problems/0541.反转字符串II.md @@ -46,7 +46,7 @@ https://leetcode-cn.com/problems/reverse-string-ii/ 使用C++库函数reverse的版本如下: -``` +```C++ class Solution { public: string reverseStr(string s, int k) { @@ -68,7 +68,8 @@ public: 那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA)道理是一样的。 下面我实现的reverse函数区间是左闭右闭区间,代码如下: -``` + +```C++ class Solution { public: void reverse(string& s, int start, int end) { @@ -101,7 +102,36 @@ public: Java: +```Java +class Solution { + public String reverseStr(String s, int k) { + StringBuffer res = new StringBuffer(); + for (int i = 0; i < s.length(); i += (2 * k)) { + StringBuffer temp = new StringBuffer(); + // 剩余字符大于 k 个,每隔 2k 个字符的前 k 个字符进行反转 + if (i + k <= s.length()) { + // 反转前 k 个字符 + temp.append(s.substring(i, i + k)); + res.append(temp.reverse()); + + // 反转完前 k 个字符之后,如果紧接着还有 k 个字符,则直接加入这 k 个字符 + if (i + 2 * k <= s.length()) { + res.append(s.substring(i + k, i + 2 * k)); + // 不足 k 个字符,则直接加入剩下所有字符 + } else { + res.append(s.substring(i + k, s.length())); + } + continue; + } + // 剩余字符少于 k 个,则将剩余字符全部反转。 + temp.append(s.substring(i, s.length())); + res.append(temp.reverse()); + } + return res.toString(); + } +} +``` Python: diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index f98051c9..93133b55 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -157,7 +157,78 @@ private: Java: +```Java +class MyLinkedList { + //size存储链表元素的个数 + int size; + //虚拟头结点 + ListNode head; + //初始化链表 + public MyLinkedList() { + size = 0; + head = new ListNode(0); + } + + //获取第index个节点的数值 + public int get(int index) { + //如果index非法,返回-1 + if (index < 0 || index >= size) { + return -1; + } + ListNode currentNode = head; + //包含一个虚拟头节点,所以查找第 index+1 个节点 + for (int i = 0; i <= index; i++) { + currentNode = currentNode.next; + } + return currentNode.val; + } + + //在链表最前面插入一个节点 + public void addAtHead(int val) { + addAtIndex(0, val); + } + + //在链表的最后插入一个节点 + public void addAtTail(int val) { + addAtIndex(size, val); + } + + // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。 + // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点 + // 如果 index 大于链表的长度,则返回空 + public void addAtIndex(int index, int val) { + if (index > size) { + return; + } + if (index < 0) { + index = 0; + } + size++; + //找到要插入节点的前驱 + ListNode pred = head; + for (int i = 0; i < index; i++) { + pred = pred.next; + } + ListNode toAdd = new ListNode(val); + toAdd.next = pred.next; + pred.next = toAdd; + } + + //删除第index个节点 + public void deleteAtIndex(int index) { + if (index < 0 || index >= size) { + return; + } + size--; + ListNode pred = head; + for (int i = 0; i < index; i++) { + pred = pred.next; + } + pred.next = pred.next.next; + } +} +``` Python: diff --git a/problems/0746.使用最小花费爬楼梯.md b/problems/0746.使用最小花费爬楼梯.md index e87f782c..b8158205 100644 --- a/problems/0746.使用最小花费爬楼梯.md +++ b/problems/0746.使用最小花费爬楼梯.md @@ -203,7 +203,26 @@ 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[] dp = new int[cost.length]; + dp[0] = cost[0]; + dp[1] = cost[1]; + for (int i = 2; i < cost.length; i++) { + dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i]; + } + //最后一步,如果是由倒数第二步爬,则最后一步的体力花费可以不用算 + return Math.min(dp[cost.length - 1], dp[cost.length - 2]); + } +} +``` Python: diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 7a06f02d..d5a8c4ed 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -122,7 +122,28 @@ public: Java: - +```Java +class Solution { + public String removeDuplicates(String S) { + Deque deque = new LinkedList<>(); + char ch; + for (int i = 0; i < S.length(); i++) { + ch = S.charAt(i); + if (deque.isEmpty() || deque.peek() != ch) { + deque.push(ch); + } else { + deque.pop(); + } + } + String str = ""; + //剩余的元素即为不重复的元素 + while (!deque.isEmpty()) { + str = deque.pop() + str; + } + return str; + } +} +``` Python: diff --git a/problems/剑指Offer05.替换空格.md b/problems/剑指Offer05.替换空格.md index 7881adf3..5f89241b 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -129,7 +129,26 @@ for (int i = 0; i < a.size(); i++) { Java: - +```Java +//使用一个新的对象,复制 str,复制的过程对其判断,是空格则替换,否则直接复制,类似于数组复制 +public static String replaceSpace(StringBuffer str) { + if (str == null) { + return null; + } + //选用 StringBuilder 单线程使用,比较快,选不选都行 + StringBuilder sb = new StringBuilder(); + //使用 sb 逐个复制 str ,碰到空格则替换,否则直接复制 + for (int i = 0; i < str.length(); i++) { + //str.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型 + if (" ".equals(String.valueOf(str.charAt(i)))){ + sb.append("%20"); + } else { + sb.append(str.charAt(i)); + } + } + return sb.toString(); + } +``` Python: