diff --git a/src/main/java/hash/GroupAnagrams.java b/src/main/java/hash/GroupAnagrams.java index c2fd3ed..0c24ec9 100644 --- a/src/main/java/hash/GroupAnagrams.java +++ b/src/main/java/hash/GroupAnagrams.java @@ -25,6 +25,7 @@ import java.util.List; */ //做出来了。 +//二刷会做 public class GroupAnagrams { //计数 public List> groupAnagrams1(String[] strs) { diff --git a/src/main/java/hash/LongestConsecutive.java b/src/main/java/hash/LongestConsecutive.java index 16ff926..6d705eb 100644 --- a/src/main/java/hash/LongestConsecutive.java +++ b/src/main/java/hash/LongestConsecutive.java @@ -23,6 +23,7 @@ import java.util.HashSet; 输出:3 */ //没做出来 +//二刷会做 public class LongestConsecutive { public int longestConsecutive(int[] nums) { // 将数组中的所有元素存入 HashSet diff --git a/src/main/java/stack/Trap.java b/src/main/java/stack/Trap.java index 9a8933b..85abaf8 100644 --- a/src/main/java/stack/Trap.java +++ b/src/main/java/stack/Trap.java @@ -15,8 +15,9 @@ import java.util.LinkedList; * 链接:https://leetcode.cn/problems/trapping-rain-water/ */ //困难题 不会 +//二刷不会 public class Trap { - //暴力解法 + //暴力解法 竖着收集雨水 public int trap1(int[] height) { int sum = 0; for (int i = 0; i < height.length; i++) { @@ -24,21 +25,35 @@ public class Trap { if (i == 0 || i == height.length - 1) { continue; } + /** + * 目的:对于每一个柱子 i,想知道它“左右两边的最高柱子”分别是多少。 + * + * 因为要接雨水,关键在于“当前位置能接多少水”取决于: + * + * 它左边的最高柱子 + * 它右边的最高柱子 + * 当前柱子的高度 + * + * + */ + int rHeight = height[i]; // 初始化右边最大高度为当前位置高度(后面会尝试找更高的) + int lHeight = height[i]; // 初始化左边最大高度为当前位置高度(后面会尝试找更高的) - int rHeight = height[i]; // 记录右边柱子的最高高度 - int lHeight = height[i]; // 记录左边柱子的最高高度 - + // 从当前位置 i 向右扫描,找出右侧最高的柱子高度 for (int r = i + 1; r < height.length; r++) { if (height[r] > rHeight) { - rHeight = height[r]; + rHeight = height[r]; // 更新右侧最高高度 } } + + // 从当前位置 i 向左扫描,找出左侧最高的柱子高度 for (int l = i - 1; l >= 0; l--) { if (height[l] > lHeight) { - lHeight = height[l]; + lHeight = height[l]; // 更新左侧最高高度 } } + int h = Math.min(lHeight, rHeight) - height[i]; if (h > 0) { sum += h; @@ -46,7 +61,19 @@ public class Trap { } return sum; } - //动态规划 + //动态规划 竖着收集雨水 + + /** + * 对于每一个柱子 i,接雨水的能力取决于它左右两边最高柱子的最小值。 + * 因此,预先构造两个数组: + * maxLeft[i] 表示从左到 i 的最大值 + * maxRight[i] 表示从右到 i 的最大值 + * 然后遍历每一个柱子(除了两端),计算: + * Math.min(maxLeft[i - 1], maxRight[i + 1]) - height[i] + * + * @param height + * @return + */ public int trap2(int[] height) { if (height.length <= 2) return 0; int n = height.length; @@ -76,7 +103,54 @@ public class Trap { return sum; } - //单调栈 + //双指针 竖着收集雨水 + /** + * 左右各有一个指针,从两端向中间走 + * 用 leftMax 和 rightMax 分别记录从左、右遇到的最高柱子 + * 每次比较 height[left] 和 height[right]: + * 谁矮,就处理谁:因为能接水的高度取决于当前方向上历史最高柱子 + * 用双指针减少了空间,整体时间仍然是 O(n) + * @param height + * @return + */ + public int trap3(int[] height) { + int left = 0, right = height.length - 1; + int leftMax = 0, rightMax = 0; + int sum = 0; + + while (left < right) { + if (height[left] < height[right]) { + if (height[left] > leftMax) { + leftMax = height[left]; + } else { + sum += leftMax - height[left]; + } + left++; + } else { + if (height[right] >= rightMax) { + rightMax = height[right]; + } else { + sum += rightMax - height[right]; + } + right--; + } + } + return sum; + } + + //单调栈 横着收集雨水 + /** + * 使用一个单调递减栈(存的是索引),遇到比栈顶高的柱子,就说明可以接水了。 + * 每当当前柱子比栈顶柱子高,就弹出栈顶作为“凹槽底部”, + * 然后新的栈顶变成“左边界”,当前柱子是“右边界” + * 这三者一起决定了可以接的水量: + * distance = i - stack.peek() - 1 + * height = min(height[i], height[stack.peek()]) - height[top] + * + * 遇到不能接水的,就把当前柱子索引压入栈中,等待后面的柱子来形成边界 + * @param height + * @return + */ public int trap(int[] height) { int sum = 0; Deque stack = new LinkedList<>(); diff --git a/src/main/java/twopointers/MaxArea.java b/src/main/java/twopointers/MaxArea.java index 0f961dd..31ddf31 100644 --- a/src/main/java/twopointers/MaxArea.java +++ b/src/main/java/twopointers/MaxArea.java @@ -16,6 +16,8 @@ package twopointers; 输入:height = [1,1] 输出:1 */ +//一刷不会 +//二刷会做 public class MaxArea { //暴力解法O(N^2) 没过所有例子 diff --git a/src/main/java/twopointers/MoveZeroes.java b/src/main/java/twopointers/MoveZeroes.java index 66703b3..50ba2f5 100644 --- a/src/main/java/twopointers/MoveZeroes.java +++ b/src/main/java/twopointers/MoveZeroes.java @@ -14,6 +14,7 @@ package twopointers; 输出: [0] */ //做出了,但时间复杂度O(N^2) +//二刷会做 ,时间复杂度on public class MoveZeroes { public void moveZeroes1(int[] nums) { for (int i = 0; i < nums.length; i++) { diff --git a/src/main/java/twopointers/ThreeSum.java b/src/main/java/twopointers/ThreeSum.java index fe36592..74e13b4 100644 --- a/src/main/java/twopointers/ThreeSum.java +++ b/src/main/java/twopointers/ThreeSum.java @@ -32,6 +32,7 @@ import java.util.List; */ //做出来了 +//二刷会做 public class ThreeSum { public List> threeSum(int[] nums) { List> ans=new ArrayList<>();