力扣hot100-双指针

题目:移动零

原题链接:移动零

在这里插入图片描述

题解

思路:快慢指针(双指针)法

  • 慢指针(l):用于标记当前非零元素应该存放的位置。
  • 快指针(h):用于遍历整个数组。
public class Test {
    public static void moveZeroes(int[] nums) {
        int l = 0, h = 0;
        for (; h < nums.length; h++) {
            if (nums[h] != 0) {
                nums[l++] = nums[h];
            }
        }
        for (; l < nums.length; l++) {
            nums[l] = 0;
        }
    }

    public static void main(String[] args) {
        int[] nums = {0, 1, 0, 3, 12};
        moveZeroes(nums);
        System.out.println(Arrays.toString(nums));
    }
}

题目:盛最多水的容器

原题链接:盛最多水的容器

在这里插入图片描述

题解

思路:双指针

public class Test {
    public static int maxArea(int[] height) {
        int l = 0;
        int h = height.length - 1;

        int area = 0;
        while (l < h) {
            area = Math.max(Math.min(height[l], height[h]) * (h - l), area);//(h - l)矩形宽度
            if (height[l] < height[h]) {
                l++;
            } else {
                h--;
            }
        }
        return area;
    }

    public static void main(String[] args) {
        int[] height = {1, 8, 6, 2, 5, 4, 8, 3, 7};
        System.out.println(maxArea(height));
    }
}

  • 如果移动较小高度的指针,有可能找到一个更高的柱子,从而增加可能的最大面积。
  • 反之,如果移动较高高度的指针,由于高度已经固定为较小值,移动较高指针只会减小宽度,不会增加高度,因此可能会导致面积减小或保持不变。

题目:三数之和

原题链接:三数之和

题解

思路:一层枚举+双指针

public class Test {
    public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums.length < 3) return res;
        Arrays.sort(nums);
        int target = 0;
        for (int i = 0; i < nums.length; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            //因为数组排序了 如果num[i]大于0  则后面不可能选出三个数和为0
            if (nums[i] > 0) break;
            target = 0 - nums[i];
            int l = i + 1, h = nums.length - 1;
            while (l < h) {
                if (nums[l] + nums[h] > target) {
                    h--;
                } else if (nums[l] + nums[h] < target) {
                    l++;
                } else if (nums[l] + nums[h] == target) {
                     // 跳过重复元素
                    while (l < h && nums[l] == nums[l + 1]) l++;
                    while (l < h && nums[h] == nums[h - 1]) h--;
                    res.add(new ArrayList<>(Arrays.asList(nums[i], nums[l], nums[h])));
                    h--;
                    l++;
                }
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] nums = {-1, 0, 1, 2, -1, -4};
        System.out.println(threeSum(nums));
    }
}

while里面的去重, 可以用下面两种方法。(为什么去重?看一个数组[-2, 0, 0, 2, 2]

 // 跳过重复元素
 while (l < h && nums[l] == nums[l + 1]) l++;
 while (l < h && nums[h] == nums[h - 1]) h--;


if (nums[l] == nums[l - 1] && ((h + 1) < nums.length && nums[h] == nums[h + 1])) {
              l++;
              h--;
              continue;
}



题目:接雨水

原题链接:接雨水

在这里插入图片描述

题解

思路:双指针
核心思想:对于任意位置 i,能够存储的雨水量取决于位置 i 左侧和右侧的最大高度中的较小值减去 height[i]。即 min(leftMax, rightMax) - height[i]。我感觉这个很好理解,理解了这个,这道题就简单了


public class T42 {
    public static int trap(int[] height) {
        if (height == null || height.length <= 2) {
            return 0;
        }

        int left = 0, right = height.length - 1;
        int leftMax = 0, rightMax = 0;
        int res = 0;

        while (left < right) {
            if (height[left] < height[right]) {
                if (height[left] >= leftMax) {
                    leftMax = height[left];
                } else {
                    res += leftMax - height[left];
                }
                left++;
            } else {
                if (height[right] >= rightMax) {
                    rightMax = height[right];
                } else {
                    res += rightMax - height[right];
                }
                right--;
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
        System.out.println(trap(height)); 
    }
}

解释代码

  • leftright 指针分别初始化为数组的最左和最右端。
  • leftMaxrightMax 分别记录遍历过程中左侧和右侧的最大高度。
  • res 用于累计存储的雨水量。

比较左右高度

if (height[left] < height[right]) {
  • 如果左侧高度小于右侧高度,则处理左侧:
    • 更新左侧最大高度
      if (height[left] >= leftMax) {
          leftMax = height[left];
      }
      
      • 如果当前左侧高度大于等于 leftMax,更新 leftMax
    • 计算左侧可以存储的雨水
      else {
          res += leftMax - height[left];
      }
      
      • 否则,当前柱子可以存储的雨水量为 leftMax - height[left]。将其累加到 res
    • 移动左指针
      left++;
      

处理右侧

else {
  • 如果右侧高度小于等于左侧高度,则处理右侧:
    • 更新右侧最大高度
      if (height[right] >= rightMax) {
          rightMax = height[right];
      }
      
      • 如果当前右侧高度大于等于 rightMax,更新 rightMax
    • 计算右侧可以存储的雨水
      else {
          res += rightMax - height[right];
      }
      
      • 否则,当前柱子可以存储的雨水量为 rightMax - height[right]。将其累加到 res
    • 移动右指针
      right--;
      

为什么双指针法有效

  • 关键思想
    • 对于任意位置 i,能够存储的雨水量取决于位置 i 左侧和右侧的最大高度中的较小值减去 height[i]。即 min(leftMax, rightMax) - height[i]
  • 左右指针
    • height[left] < height[right] 时,右侧的高度至少是 height[right],这意味着左侧的最大高度决定了当前柱子 left 的存储量。
    • 同理,当 height[left] >= height[right] 时,左侧的高度至少是 height[left],这意味着右侧的最大高度决定了当前柱子 right 的存储量。

力扣有一位大佬给出5种方法,确实让人佩服。5种解答


❤觉得有用的可以留个关注~~❤

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值