LeetCode Hot100 - 双指针篇

前言

挑战一个月刷完力扣的hot100,记录一下每题的思路~

这次是双指针相关的题目

(1)283. 移动零

①双指针,找第一个 和零后第一个非零数字,然后交换

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int num=0, zero=0; // 记录零后第一个数字和第一个零
        while(num!=nums.length){
            if(num<zero)num++; // 保证找到零后的非零数字
            else if(nums[num]==0)num++; // 找非零
            else if(nums[zero]!=0)zero++; // 找零
            else { // 交换
                nums[zero]=nums[num];
                nums[num]=0;
                num++;
                zero++;
            }
        }
    }
}

②双指针,左指针左侧 均为非零数,右指针在左指针后找第一个非零数,找到就交换

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int l=0, r=0; // 左指针左侧均非零,右指针找左指针后第一个非零数
        while(r<nums.length){
            if(nums[r]!=0){ // 找到非零数就与左指针交换
                int temp = nums[l];
                nums[l]=nums[r];
                nums[r]=temp;
                l++;
            }
            r++;
        }
    }
}

(2)11. 盛最多水的容器

双指针,从左右边界开始,必定移动左右边界其中一个,对于较小的那边,不可能在产生更大的容量情况,于是丢弃该边 ,问题转换为新的数组边界,不断丢弃较小的边。一直保留最长边,然后迭代考虑宽度

java 复制代码
class Solution {
    public int maxArea(int[] height) {
        int res=0, l=0, r=height.length-1;
        while(l<r){
            res=Math.max(res,(r-l)*Math.min(height[l],height[r]));
            // 小的那边不可能再产生更大的容量,丢弃该边,转换为新的数组边界情况
            if(height[l]<=height[r])l++;
            else r--;
        }
        return res;
    }
}

(3)15. 三数之和

排序+双指针,先排序,迭代确定第一个数 ,剩下两个数使用双指针选取。注意第一个数不能重复选择,后续两个数选定后还要用while去重。

边界条件:数组长度不够、第一个数下标不大于n-2、前三个数和大于0、第一个数和最后两个数和小于零

java 复制代码
class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> threeSum(int[] nums) {
        if(nums.length<3)return res; // 长度不够
        Arrays.sort(nums); // 排序
        int n = nums.length;
        for(int i=0;i<n-2;i++){
            if(nums[i]+nums[i+1]+nums[i+2]>0)break; // 最小和大于零,直接返回
            if(nums[i]+nums[n-2]+nums[n-1]<0)continue; // 最大和小于零,第一个数跳过
            if(i!=0&&nums[i]==nums[i-1])continue; // 跳过重复
            int l=i+1, r=n-1;
            while(l<r){ // 双指针寻找
                int sum = nums[l]+nums[r];
                if(sum+nums[i]<0)l++; // 和小
                else if(sum+nums[i]>0)r--; // 和大
                else { // 和为零
                    res.add(new ArrayList<>(Arrays.asList(nums[i],nums[l],nums[r])));
                    l++;
                    r--;
                    // 跳过重复
                    while(l<r&&nums[l]==nums[l-1])l++;
                    while(l<r&&nums[r]==nums[r+1])r--;
                }
            }
        }
        return res;
    }
}

(4)42. 接雨水

①动规,从左到右记录左侧最高柱子,从右到左记录右侧最高柱子,计算并存储每个位置 两边的最大高度,然后遍历每个位置计算接水量

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 res=0;
        for(int i=0;i<n;i++)res+=Math.min(leftMax[i],rightMax[i])-height[i];
        return res;
    }
}

②单调栈,栈底最大,栈只记录一次接水部分的左侧柱子 。若出现出现高(left)、低(top)、高(i)情况,表示有接水 出现,计算接水部分。top表示接水的低处,取top先判断左侧是否有更高柱,即left是否存在,如果不存在表示不形成接水,直接break找下一个接水部分

java 复制代码
class Solution {
    public int trap(int[] height) {
        int res=0;
        Deque<Integer> stack = new ArrayDeque<>(); // 单调栈,栈底最大
        for(int i=0;i<height.length;i++){
            while(!stack.isEmpty()&&height[i]>height[stack.peek()]){
                int top=stack.pop(); // 低部分,先判断左侧是否有更高柱
                if(stack.isEmpty())break; // top左侧更高柱,不形成接水
                // 出现高(left)、低(top)、高(i)情况,计算接水部分
                int left=stack.peek();
                int curWidth=i-left-1; 
                int curHeight=Math.min(height[left],height[i])-height[top];
                res += curWidth*curHeight;
            }
            stack.push(i);
        }
        return res;
    }
}

③双指针,左右两个指针遍历,并记录左右 已遍历的最高柱子高度 。每次会移动更矮指针,因此没移动 的指针为目前已遍历最高 柱子,保证移动 的指针处能接水,并根据移动侧的最高柱子高度计算接水量

java 复制代码
class Solution {
    public int trap(int[] height) {
        int res=0, l=0, r=height.length-1;
        int maxL=0, maxR=0;
        while(l<r){
            // 记录左右已遍历的最高柱子
            maxL = Math.max(maxL,height[l]);
            maxR = Math.max(maxR,height[r]);
            // 每次会移动更矮指针,因此没移动的指针为目前已遍历最高柱子
            if(height[l]<height[r]){ // 因此r为目前最高柱子,l根据maxL蓄水
                res+=maxL-height[l];
                l++;
            }
            else{
                res+=maxR-height[r]; // 因此l为最高柱子,r根据maxR蓄水
                r--;
            }
        }
        return res;
    }
}

④双指针,主要思想与③同,但判断接水条件不同,个人感觉更好理解 一点。左右两个指针遍历,并记录左右已遍历的最高柱子高度。每次判断最高柱子在哪侧 ,即更矮 侧的柱子一定跟接水,根据更矮侧的最高柱子高度蓄水

java 复制代码
class Solution {
    public int trap(int[] height) {
        int res=0, l=0, r=height.length-1;
        int maxL=0, maxR=0;
        while(l<r){
            // 记录左右已遍历的最高柱子
            maxL = Math.max(maxL,height[l]);
            maxR = Math.max(maxR,height[r]);
            if(maxL<maxR){ // 最高柱子在右侧,l处一定能蓄水
                res+=maxL-height[l];
                l++;
            }
            else{
                res+=maxR-height[r]; // 最高柱子在左侧,r处一定能蓄水
                r--;
            }
        }
        return res;
    }
}

总结

①双指针用于交换查找指定条件的情况

移动零,一个指针指向已判断的序列,一个指针寻找后续第一个非零数,然后交换

盛最多水的容器,利用更小边界不会再有更大容量的特点,使用双指针不断缩小边界,找到最大容量的情况

三数之和,先排序,迭代确定第一个数,使用双指针找到指定和的两个数。注意去重和边界条件剪枝

接雨水 ,有三种解题方式。第一种动规 ,记录每个位置左右侧最高柱,然后遍历计算每个位置接水量。第二种单调栈 ,记录每个节水部分的左侧柱子,出现高低高时计算接水量,注意判断left不存在的情况。第三种双指针,左右两侧指针遍历,并分别记录左右最高柱高度,可理解为每次不移动的指针表示已知最高柱,另一侧接水;也可理解为直接比较最高处在哪侧,另一侧接水

相关推荐
艾醒2 小时前
大模型面试题剖析:大模型微调与训练硬件成本计算
人工智能·后端·算法
啊嘞嘞?2 小时前
力扣(滑动窗口最大值)
算法·leetcode·职场和发展
快递鸟2 小时前
ISV系统开发中物流接口的第三方模块对接:技术选型与集成实践
算法
墨染点香2 小时前
LeetCode 刷题【53. 最大子数组和】
数据结构·算法·leetcode
2501_924879263 小时前
客流特征识别误报率↓76%!陌讯多模态时序融合算法在智慧零售的实战解析
大数据·人工智能·算法·目标检测·计算机视觉·视觉检测·零售
北京地铁1号线3 小时前
广告推荐模型2:因子分解机(Factorization Machines, FM)
人工智能·算法·推荐算法
七十二小時4 小时前
力扣热题——前K个高频元素
数据结构·算法·leetcode
500佰4 小时前
AI手办,Gemini 2.5 Flash Image 可一键制作高一致性人物手办
算法
愚润求学5 小时前
【贪心算法】day3
c++·算法·leetcode·贪心算法
空白到白5 小时前
算法练习-合并两个有序数组
数据结构·python·算法