Update Leetcode 题解 - 双指针.md

补充三数之和、接雨水、最小覆盖子串,并配图说明接雨水的水位计算。
This commit is contained in:
CyC2018
2026-10-25 21:34:15 +08:00
parent 709067f4f2
commit fce2082f1a
3 changed files with 191 additions and 0 deletions
+124
View File
@@ -8,6 +8,9 @@
* [5. 归并两个有序数组](#5-归并两个有序数组)
* [6. 判断链表是否存在环](#6-判断链表是否存在环)
* [7. 最长子序列](#7-最长子序列)
* [8. 三数之和](#8-三数之和)
* [9. 接雨水](#9-接雨水)
* [10. 最小覆盖子串](#10-最小覆盖子串)
<!-- GFM-TOC -->
@@ -290,3 +293,124 @@ private boolean isSubstr(String s, String target) {
return j == target.length();
}
```
## 8. 三数之和
15\. 3Sum (Medium)
[Leetcode](https://leetcode.com/problems/3sum/) / [力扣](https://leetcode.cn/problems/3sum/)
```text
Input: nums = [-1, 0, 1, 2, -1, -4]
Output: [[-1, -1, 2], [-1, 0, 1]]
```
题目描述:找出所有和为 0 且不重复的三元组。
先排序,然后枚举第一个数 nums[i],在它右边用第 1 题的双指针方法寻找和为 -nums[i] 的两个数。去重的关键是跳过相同的值:i 跳过与前一个数相同的值,找到一组解之后,两个指针也跳过相同的值。时间复杂度为 O(N<sup>2</sup>)。
```java
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ret = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int l = i + 1, h = nums.length - 1;
while (l < h) {
int sum = nums[i] + nums[l] + nums[h];
if (sum < 0) {
l++;
} else if (sum > 0) {
h--;
} else {
ret.add(Arrays.asList(nums[i], nums[l], nums[h]));
while (l < h && nums[l] == nums[l + 1]) {
l++;
}
while (l < h && nums[h] == nums[h - 1]) {
h--;
}
l++;
h--;
}
}
}
return ret;
}
```
## 9. 接雨水
42\. Trapping Rain Water (Hard)
[Leetcode](https://leetcode.com/problems/trapping-rain-water/) / [力扣](https://leetcode.cn/problems/trapping-rain-water/)
```text
Input: height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
Output: 6
```
位置 i 上方能存的水,取决于它左边最高的柱子和右边最高的柱子中较矮的那一个:water[i] = min(leftMax, rightMax) - height[i]。
用两个指针从两端向中间移动,分别维护 leftMax 和 rightMax。如果 leftMax < rightMax,左指针处的水位只由 leftMax 决定,因为右边已经有一根不低于 rightMax 的柱子,可以直接结算左指针并右移;反之结算右指针并左移。
<div align="center"> <img src="pics/trapping-rain-water.png" width="560px"/> </div><br>
```java
public int trap(int[] height) {
int l = 0, r = height.length - 1;
int leftMax = 0, rightMax = 0, ret = 0;
while (l < r) {
leftMax = Math.max(leftMax, height[l]);
rightMax = Math.max(rightMax, height[r]);
if (leftMax < rightMax) {
ret += leftMax - height[l++];
} else {
ret += rightMax - height[r--];
}
}
return ret;
}
```
## 10. 最小覆盖子串
76\. Minimum Window Substring (Hard)
[Leetcode](https://leetcode.com/problems/minimum-window-substring/) / [力扣](https://leetcode.cn/problems/minimum-window-substring/)
```text
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
```
题目描述:找出 s 中包含 t 所有字符(包括重复字符)的最短子串。
使用滑动窗口。need[c] 表示窗口还缺几个字符 c,missing 表示一共还缺几个字符。右指针不断扩大窗口,直到 missing 为 0,此时窗口包含了 t 的所有字符;然后移动左指针缩小窗口,在窗口仍然满足条件时更新答案。
```java
public String minWindow(String s, String t) {
int[] need = new int[128];
for (char c : t.toCharArray()) {
need[c]++;
}
int missing = t.length(), start = 0, minLen = Integer.MAX_VALUE;
for (int l = 0, r = 0; r < s.length(); r++) {
if (need[s.charAt(r)]-- > 0) {
missing--;
}
while (missing == 0) {
if (r - l + 1 < minLen) {
minLen = r - l + 1;
start = l;
}
if (++need[s.charAt(l++)] > 0) {
missing++;
}
}
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
}
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+67
View File
@@ -0,0 +1,67 @@
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="290" viewBox="0 0 600 290">
<style>
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #666; font-size: 12px; }
.title { font-weight: bold; font-size: 15px; fill: #777; text-anchor: middle; }
.b { font-weight: bold; }
.c { text-anchor: middle; }
.e { text-anchor: end; }
.note { fill: #C0605A; }
.ok { fill: #6A9F68; }
.sub { font-size: 11px; fill: #888; }
.mono { font-family: Menlo, Consolas, monospace; }
.arrow { stroke: #666; stroke-width: 1.3; fill: none; marker-end: url(#a); }
.red { stroke: #C0605A; marker-end: url(#r); }
.green { stroke: #6A9F68; marker-end: url(#g); }
.dash { stroke-dasharray: 5 4; }
.line { stroke: #666; stroke-width: 1.3; fill: none; }
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
.shadow { fill: #C0C0C0; }
</style>
<defs>
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#666" stroke-width="1.6"/>
</marker>
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#C0605A" stroke-width="1.6"/>
</marker>
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M1,1 L9,5 L1,9" fill="none" stroke="#6A9F68" stroke-width="1.6"/>
</marker>
</defs>
<rect width="100%" height="100%" fill="#FFFFFF"/>
<text x="300" y="28" class="title">接雨水</text>
<text x="78" y="246" class="c sub">0</text>
<rect x="98" y="190" width="36" height="40" fill="#9E9E9E"/>
<text x="116" y="246" class="c sub">1</text>
<rect x="136" y="190" width="36" height="40" fill="#D6EEF8"/>
<text x="154" y="246" class="c sub">2</text>
<rect x="174" y="150" width="36" height="80" fill="#9E9E9E"/>
<text x="192" y="246" class="c sub">3</text>
<rect x="212" y="150" width="36" height="40" fill="#D6EEF8"/>
<rect x="212" y="190" width="36" height="40" fill="#9E9E9E"/>
<text x="230" y="246" class="c sub">4</text>
<rect x="250" y="150" width="36" height="80" fill="#D6EEF8"/>
<text x="268" y="246" class="c sub">5</text>
<rect x="288" y="150" width="36" height="40" fill="#D6EEF8"/>
<rect x="288" y="190" width="36" height="40" fill="#9E9E9E"/>
<text x="306" y="246" class="c sub">6</text>
<rect x="326" y="110" width="36" height="120" fill="#9E9E9E"/>
<text x="344" y="246" class="c sub">7</text>
<rect x="364" y="150" width="36" height="80" fill="#9E9E9E"/>
<text x="382" y="246" class="c sub">8</text>
<rect x="402" y="150" width="36" height="40" fill="#D6EEF8"/>
<rect x="402" y="190" width="36" height="40" fill="#9E9E9E"/>
<text x="420" y="246" class="c sub">9</text>
<rect x="440" y="150" width="36" height="80" fill="#9E9E9E"/>
<text x="458" y="246" class="c sub">10</text>
<rect x="478" y="190" width="36" height="40" fill="#9E9E9E"/>
<text x="496" y="246" class="c sub">11</text>
<line x1="54" y1="230" x2="516" y2="230" class="line"/>
<line x1="174" y1="150" x2="364" y2="150" class="line dash"/>
<text x="168" y="144" class="e note">leftMax = 2</text>
<text x="368" y="124" class="note">rightMax = 3</text>
<line x1="268" y1="86" x2="268" y2="146" class="arrow red"/>
<text x="208" y="80" class="c">位置 5 存水 min(2, 3) - 0 = 2</text>
<text x="300" y="278" class="c sub">灰色为柱子,浅蓝色为积水,总共 6</text>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB