LeetCode Hot100 双指针专项题解笔记

前言

双指针是数组类题目高频解法,核心思想:用两个指针代替双重循环,把 O ( n 2 ) O(n^2) O(n2) 复杂度优化至 KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲O(n)\)。

常见两类模式:

  1. 同向双指针(快慢指针):左右指针一起从左向右移动,典型场景:移动零、去重
  2. 相向双指针(左右指针):左指针起始左端、右指针起始右端,向中间收拢,典型场景:盛最多水容器、三数之和、接雨水

核心准则:移动指针的策略必须有明确单调性,保证不会漏掉最优解。

1. 283. 移动零(同向快慢双指针)

思路

left 指向待填充非零元素的位置,right 不断遍历数组;遇到非零数就交换左右指针元素,保证非零元素相对顺序不变,所有零被挤到数组末尾。

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length;
        // left:下一个非零元素应该存放的位置
        int left = 0;
        // right:遍历探测指针
        int right = 0;
        while (right < n) {
            // right找到非0元素,和left位置交换
            if (nums[right] != 0) {
                swap(nums, left, right);
                left++; // left位置已存入有效值,右移
            }
            right++; // 探测指针持续向右
        }
    }

    private void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
}

// 重点备注:同向双指针,快慢分离;只在探测到非零元素时移动慢指针,零元素会自然留在left左侧以外区域。

// 进阶优化:可以不交换,先把非零值前移,最后末尾统一赋值0,减少交换操作次数。

2. 11. 盛最多水的容器(相向双指针)

思路

左右指针分别在两端,计算当前容器面积;移动高度更小的一侧指针

原理:容器高度由短板决定,如果移动长板,宽度缩小、高度上限不变,面积一定不会更大;只有移动短板,才有可能找到更高边界获得更大面积。

java 复制代码
class Solution {
    public int maxArea(int[] height) {
        // 左指针起点
        int l = 0;
        // 右指针起点
        int r = height.length - 1;
        int max = 0; // 保存最大面积
        while (l < r) {
            // 容器高度 = 两侧高度最小值;宽度 = r-l
            int area = Math.min(height[l], height[r]) * (r - l);
            max = Math.max(area, max);
            // 核心:移动高度更小的指针
            if (height[l] < height[r]) {
                l++;
            } else {
                r--;
            }
        }
        return max;
    }
}

// 重点备注:相向双指针经典题,指针移动逻辑是考点 ,切忌随机移动指针。

// 易错坑:不要写成 (r-1) 计算宽度,宽度直接 r-l

3. 15. 三数之和(排序 + 相向双指针 + 去重)

思路

  1. 先数组排序,固定第一个元素 first;
  2. second 为 first+1(左指针),third 数组末尾(右指针);
  3. 三数和 > 0:右指针左移;和 < 0:左指针右移;和=0记录答案;
  4. 必须增加去重逻辑,避免重复三元组。
java 复制代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums); // 排序是双指针使用前提
        List<List<Integer>> ans = new ArrayList<>();

        // 固定第一个数
        for (int first = 0; first < n; first++) {
            // 对first去重:和上一个数字相同直接跳过
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            int target = -nums[first]; // 需要 second + third = target
            int third = n - 1; // 右指针初始在末尾

            // second 左指针,从first下一位开始
            for (int second = first + 1; second < n; second++) {
                // second去重
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }
                // 和大于目标值,右指针持续左移
                while (second < third && nums[second] + nums[third] > target) {
                    third--;
                }
                // 指针相遇,无需继续
                if (second == third) {
                    break;
                }
                // 找到合法三元组
                if (nums[second] + nums[third] == target) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[first]);
                    list.add(nums[second]);
                    list.add(nums[third]);
                    ans.add(list);
                }
            }
        }
        return ans;
    }
}

// 重点备注:三数之和 = 一层循环 + 两数之和(相向双指针)。

// 重中之重:三层去重逻辑,first、second重复元素都需要跳过,否则出现重复答案。

// 优化写法:内层可以不用for循环second,改用while实现双指针,可读性更好。

4. 42. 接雨水(前置:预处理数组解法,拓展双指针优化)

思路(预处理左右最大高度数组版本)

位置 i 能接住雨水 = min(左侧最高柱子高度, 右侧最高柱子高度) - 当前柱子高度

先预处理 leftMax 数组:每个位置左边最高高度;rightMax数组:每个位置右边最高高度。

java 复制代码
class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) return 0;

        int[] leftMax = new int[n];
        leftMax[0] = height[0];
        // 正向遍历,求每个位置左侧最大高度
        for (int i = 1; i < n; i++) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
        }

        int[] rightMax = new int[n];
        rightMax[n - 1] = height[n - 1];
        // 反向遍历,求每个位置右侧最大高度
        for (int i = n - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);
        }

        int ans = 0;
        // 逐个位置累加雨水
        for (int i = 0; i < n; i++) {
            // 左右挡板短板 - 当前高度
            ans += Math.min(leftMax[i], rightMax[i]) - height[i];
        }
        return ans;
    }
}

// 重点备注:预处理方法直观,便于理解原理;缺点占用额外数组。

// 进阶相向双指针思路:维护leftMax、rightMax两个变量,左右指针向中间移动;哪边挡板更小,就计算当前一侧雨水,空间复杂度压缩到O(1)。

双指针题型总结

同向双指针(快慢指针)

适用场景:数组元素就地移动、过滤元素、滑动窗口

代表题目:移动零、删除有序数组重复项

相向双指针(左右指针)

适用场景:有序数组查找两数/三数之和、两侧边界约束问题

代表题目:盛最多水容器、三数之和、接雨水(优化版)

通用做题思考步骤

  1. 判断数组是否需要排序;
  2. 确定指针初始位置;
  3. 明确什么时候移动哪个指针(核心难点,要有单调性证明);
  4. 重复类题目额外增加去重判断;
  5. 边界处理:指针越界、两指针相遇终止条件。
相关推荐
懿路向前1 小时前
【HarmonyOS学习笔记】2026-07-24 | textProcessing 实体识别与踩坑实录
笔记·学习·边缘计算·harmonyos
闪电悠米1 小时前
力扣hot100-54.螺旋矩阵-模拟边界控制详解
算法·leetcode·矩阵
变量未定义~2 小时前
虚拟节点-星石传送阵(4星)、强连通分量
数据结构·算法
春生野草2 小时前
C基础--八大排序(个人笔记)
c语言·笔记·排序算法
IT方大同2 小时前
C语言分支与循环语句
c语言·开发语言·算法
待磨的钝刨2 小时前
深入理解主成分分析(PCA)
人工智能·线性代数·算法·机器学习
caimouse2 小时前
MM 学习笔记 09:进程会话与工作集
笔记·学习·reactos
星恒随风3 小时前
C++ 继承进阶:默认成员函数、多继承、虚继承与组合设计
开发语言·c++·笔记·学习
foo1st3 小时前
MySQL 8.0(Windows)升级笔记
数据库·笔记·mysql