当前位置: 首页 > article >正文

LeetCode 热题 100 | 双指针

双指针基础

  • 通过两个指针在一个for循环下完成两个for循环的工作。能够有效降低多层for循环中一个循环的时间复杂度。
  • 双指针求和需要先排序数组,不然不知道该移动哪个指针。

283. 移动零

题目讲解:LeetCode
重点:

  1. 左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。

思路:

  1. 两个指针,左指针指向已经处理好的序列尾部,右指针指向待处理序列的头部。遍历数组,如果右指针的元素不为0,则与左指针指向的0交换。整个数组没有0也只会与自己交换直到发现第一个0右指针才会比左指针快。

复杂度:

  • n 为数组长度。
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
public void moveZeroes(int[] nums) {
    int left = 0, right = 0;
    while (right < nums.length) {
    	// 重点: 不等于0时是两个指针同步移动
    	// 等于0时只移动right来寻找下一个非0
        if (nums[right] != 0) {
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            left++;
        }
        right++;
    }
}

11. 盛最多水的容器

题目讲解:LeetCode
重点:

  1. 左指针指向容器左边界,右指针指向容器右边界。

思路:

  1. 两个指针,左指针指向容器左边界,右指针指向容器右边界。每次移动高度较低的指针。
  • 如果移动高的那一边,会有两种情况:
    1.下一根柱子的高度比现在高,高度还取最小值低的那边,最大水量比原来小。
    2.下一根柱子的高度比现在低,高度比原来的最小值还小,最大水量比原来小。
  • 如果移动低的那一边,会有两种情况:
    1.下一根柱子的高度比现在高,高度就可以取更高的值,最大水量不一定比原来小
    2.下一根柱子的高度比现在低,高度比原来的最小值还小,最大水量比原来小。

复杂度:

  • N 是数组长度。
  • 时间复杂度:O(N)
  • 空间复杂度:O(1)
public int maxArea(int[] height) {
    int left = 0, right = height.length - 1;
    int result = 0;
    while (left < right) {
        int water = (right - left) * Math.min(height[left], height[right]);
        result = Math.max(water, result);
        // 重点: 每次都只移动较矮的
        if (height[left] > height[right]) right--;
        else left++;
    }
    return result;
}

15. 三数之和

题目讲解:LeetCode
重点:

  1. 双指针。先从小到大排序数组,然后固定一个数使用双指针往中间靠拢即可。根据和的大小来判断该移动左指针还是右指针。

思路:

  1. 从小到大排序数组。
  2. 固定一个数,如果该数和上一个数相同,则已经探索过该数,跳过。
  3. 左指针在i + 1,右指针在nums.length - 1。如果和小于0,左指针加1。如果和大于0,右指针减1。如果和为0,则把left和right移动到不重复的元素上,方便接着探索其他组合。

复杂度:

  • N 是数组长度
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(N)
public List<List<Integer>> threeSum(int[] nums) {
	// 重点: 双指针需要排序数组
    Arrays.sort(nums);
    List<List<Integer>> result = new ArrayList<>();
    // 重点: 固定a, 根据和的大小来移动b和c
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] > 0) return result;
        if (i >= 1 && nums[i] == nums[i - 1]) continue;
        int left = i + 1;
        int right = nums.length - 1;
        while (left < right) {
            int sum = nums[i] + nums[left] + nums[right];
            if (sum > 0) {
                right--;
            } else if (sum < 0) {
                left++;
            } else {
                result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                while (left < right && nums[left + 1] == nums[left]) left++;
                while (left < right && nums[right - 1] == nums[right]) right--;
                left++;
                right--;
            }
        }
    }
    return result;
}

42. 接雨水

题目讲解:LeetCode
重点:

  1. 一列一列的计算水。
  2. 动态规划可以提前计算好每列左和右的最高值。
  3. 双指针可以实时计算左和右指针的左边最高值和右边最高值。

思路:

  • 动态规划:
  1. 利用动态规划先计算每列左和右的最高高度
  2. 再遍历每列,根据最高高度计算当前列的雨水。
  • 双指针:
  1. 两个指针,一个指针在开头,一个指针在末尾。leftMax和rightMax分别记录最大值。
  2. 当出现凹槽的时候:
    如果是left出现的凹槽,用leftMax减即可,因为left的右手边最大值肯定大于等于rightMax,我们本意是要取leftMax和rightMax的最小值来计算left这一列的water。
    如果是right出现的凹槽,用rightMax减即可,因为right的左手边最大值肯定大于等于leftMax,我们本意是要取leftMax和rightMax的最小值来计算right这一列的water。

复杂度:

  • N 是数组长度
  • 动态规划:
    时间复杂度:O(n)
    空间复杂度:O(n)
  • 双指针:
    时间复杂度:O(n)
    空间复杂度:O(1)
public int trap(int[] height) {
	// 重点: 动态规划提前计算好每列左和右的最高高度
    int[] maxLeft = new int[height.length];
    maxLeft[0] = height[0];
    for (int i = 1; i < height.length; i++) maxLeft[i] = Math.max(height[i], maxLeft[i - 1]);
    
    int[] maxRight = new int[height.length];
    maxRight[height.length - 1] = height[height.length - 1];
    for(int i = height.length - 2; i >= 0; i--) maxRight[i] = Math.max(height[i], maxRight[i + 1]);
    
    int result = 0;
    for (int i = 0; i < height.length; i++) {
        int colWater = Math.min(maxLeft[i], maxRight[i]) - height[i];
        result += colWater;
    }
    return result;
}
public int trap(int[] height) {
    int left = 0, right = height.length - 1;
    int leftMax = 0, rightMax = 0;
    int result = 0;
    // 重点: 两个指针往中间靠拢
    // 那么leftMax是left左边最高的, rightMax是right右边最高的
    while (left < right) {
        leftMax = Math.max(leftMax, height[left]);
        rightMax = Math.max(rightMax, height[right]);
        // 重点: 出现凹槽了
        // 如果是左矮与右, left的右手边最高值肯定大于等于rightMax, 因为right是右往左遍历, 肯定是能接住leftMax的
        // 而left右手边出现更矮的柱子也不妨碍这一列water的计算
        // 如果是右矮与左, right的左手边最高值肯定大于等于leftMax, 因为left是左往右遍历, 肯定是能接住rightMax的
        // 而right左手边出现更矮的柱子也不妨碍这一列water的计算
        if (height[left] < height[right]) {
            result += leftMax - height[left];
            left++;
        } else {
            result += rightMax - height[right];
            right--;
        }
    }
    return result;
}

http://www.kler.cn/a/500126.html

相关文章:

  • Objective-C语言的语法
  • 关于物联网的基础知识(二)——物联网体系结构分层
  • Qt资源文件以及文件加密
  • Git:Cherry-Pick 的使用场景及使用流程
  • 基于Java+SpringMvc+Vue技术的宠物分享平台
  • 省森林防火应急指挥系统
  • 2024 年 8 月公链行业研报:Layer 1、比特币 Layer 2 和以太坊 Layer 2 趋势分析
  • 构建高效的进程池:深入解析C++实现
  • 解决:离线部署Docker容器(使用Docker现有容器生成镜像,将镜像打包成tar并发布到离线服务器中)
  • uni-app支付宝、微信小程序实现拨打电话uni.makePhoneCall
  • 《拉依达的嵌入式\驱动面试宝典》—操作系统篇(九)
  • 又更新了一个list转树状结构的工具类
  • 辅助--Inspector
  • QT + Opencv 实现灰度模板匹配
  • SVM赛道概览:MoveVM落地,SVM能走多远
  • 食堂采购系统源码:基于PHP的校园食堂供应链管理平台开发全解析
  • web前端-html
  • phpenc加密程序源码
  • 快速上手Git——Windows系统下Git的安装与简单使用流程
  • 【网络云SRE运维开发】2025第2周-每日【2025/01/09】小测-【第9章 VRRP原理及基本配置考试】理论和实操解析
  • 代理模式简介
  • 【深度学习】运算符
  • 树莓集团:数字资产什么意思?包括哪些?