双指针算法题汇总

双指针算法题目

在这里插入图片描述

移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]输出: [0]

提示:

  • 1 <= nums.length <= 10(4)

  • -2(31) <= nums[i] <= 2(31) - 1

进阶:你能尽量减少完成的操作次数吗?

Related Topics

数组

双指针

class Solution {
    public void moveZeroes(int[] nums) {
        int dest=-1;
        int cur=0;
        for(int i=0;i<nums.length;i++){
            if(nums[cur]!=0){
                int temp=nums[cur];
                nums[cur]=nums[dest+1];
                nums[dest+1]=temp;
                dest++;
            }
            cur++;
        }
    }
}

覆写零

给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

示例 1:

输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]

示例 2:

输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]

提示:

  • 1 <= arr.length <= 10(4)

  • 0 <= arr[i] <= 9

Related Topics

数组

双指针

class Solution {
    public void duplicateZeros(int[] arr) {
        int n = arr.length;
        int cur = 0;
        int dest = -1;

        // 第一遍遍历:计算目标位置
        while (cur < n) {
            // 根据当前元素是否为0更新dest
            if (arr[cur] == 0) {
                dest += 2;
            } else {
                dest += 1;
            }

            // 当dest即将超出范围时停止
            if (dest >= n - 1) {
                break;
            }

            // 统一后移cur指针
            cur++;
        }

        // 处理最后一个元素是0但空间不足的情况
        if (dest >= n) {
            arr[n - 1] = 0;
            cur--;
            dest = n - 2;
        }

        // 第二遍遍历:从后往前复制
        while (cur >= 0 && dest >= 0) {
            if (arr[cur] != 0) {
                arr[dest] = arr[cur];
                dest--;
            } else {
                arr[dest] = 0;
                dest--;
                if (dest >= 0) {
                    arr[dest] = 0;
                    dest--;
                }
            }
            cur--;
        }
    }
}

快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。

  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。

  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n快乐数 就返回 true ;不是,则返回 false

示例 1:

输入:n = 19
输出:true
解释:
1(2) + 9(2) = 82
8(2) + 2(2) = 68
6(2) + 8(2) = 100
1(2) + 0(2) + 0(2) = 1

示例 2:

输入:n = 2
输出:false

提示:

  • 1 <= n <= 2(31) - 1

Related Topics

哈希表

数学

双指针

class Solution {
    public int bitSum(int n){
        int sum=0;
        while(n!=0){
            int temp=n%10;
            sum+=temp*temp;
            n/=10;
        }
        return sum;
    }
    public boolean isHappy(int n) {
        int slow=n;
        int fast=bitSum(n);
        while(fast!=slow){
            slow=bitSum(slow);
            fast=bitSum(bitSum(fast));
        }
        return slow==1;
    }
}

盛水最多的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

在这里插入图片描述

示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

提示:

  • n == height.length

  • 2 <= n <= 10(5)

  • 0 <= height[i] <= 10(4)

Related Topics

贪心

数组

双指针

class Solution {
    public int maxArea(int[] height) {
        int left=0,right=height.length-1;
        int ret=0;
        while(left<right){
            int v=Math.min(height[left],height[right])*(right-left);
            ret=Math.max(ret,v);
            if(height[left]<height[right]) left++;
            else right--;
        }
        return ret;
    }
}

有效三角形的个数

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是:
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

示例 2:

输入: nums = [4,2,3,4]
输出: 4

提示:

  • 1 <= nums.length <= 1000

  • 0 <= nums[i] <= 1000

Related Topics

贪心

数组

双指针

二分查找

排序

class Solution {
    public int triangleNumber(int[] nums) {
        Arrays.sort(nums);
        int res = 0;
        for (int i = nums.length - 1; i >= 2; i--) {
            int left = 0, right = i - 1;
            while (left < right) {
                if (nums[left] + nums[right] > nums[i]) {
                    res += right - left;
                    right--;
                } else {
                    left++;
                }
            }
        }
        return res;
    }
}

两数之和

购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。

示例 1:

输入:price = [3, 9, 12, 15], target = 18
输出:[3,15] 或者 [15,3]

示例 2:

输入:price = [8, 21, 27, 34, 52, 66], target = 61
输出:[27,34] 或者 [34,27]

提示:

  • 1 <= price.length <= 10^5

  • 1 <= price[i] <= 10^6

  • 1 <= target <= 2*10^6

class Solution {
    public int[] twoSum(int[] price, int target) {
        int left=0;
        int right=price.length-1;
        while(left<right){
            int sum=price[left]+price[right];
            if(sum>target) right--;
            else if(sum<target) left++;
            else return new int[] {price[left],price[right]};
        }
        //照顾编辑器
        return new int[]{0};
    }
}

三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000

  • -10(5) <= nums[i] <= 10(5)

Related Topics

数组

双指针

排序

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        //排序
        Arrays.sort(nums);
        int n = nums.length;
        //利用双指针解决问题
        for (int i = 0; i < n; ) {
            if (nums[i] > 0) break;
            int left = i + 1, right = n - 1;
            int target = -nums[i];
            while (left < right) {
                int sum = nums[left] + nums[right];
                if (sum > target) right--;
                else if (sum < target) left++;
                else {
                    res.add(new ArrayList<Integer>(Arrays.asList(nums[i], nums[left], nums[right])));
                    left++;
                    right--;
                    //去重
                    while (left < right && nums[left] == nums[left - 1]) left++;
                    while (left < right && nums[right] == nums[right + 1]) right--;
                }
            }
            i++;
            while (i < n && nums[i] == nums[i - 1]) i++;
        }
        return res;
    }
}
  • 可能存在的问题:

    ArrayIndexOutOfBoundsException 错误是由于数组中数组索引越界导致的,具体问题出在对变量 i 的边界判断上。

    错误分析:

    在你的代码中,有这样一行:

    while (nums[i] == nums[i - 1] && i < n) i++;
    

    这里的问题是判断条件的顺序。当 i 已经等于 n 时,先判断 nums[i] == nums[i - 1] 会导致访问 nums[n],而数组的最大索引是 n-1,从而引发索引越界异常。

    正确的做法是先判断 i < n,确保索引在有效范围内,再进行元素比较,就像正确代码中那样:

    while (i < n && nums[i] == nums[i - 1]) i++;
    

    修正后的完整代码如下:

    这个修正虽然只是调整了判断条件的顺序,但却非常关键。在处理数组索引时,始终应该先确保索引在有效范围内,再进行元素访问,这是避免数组索引越界异常的重要原则。

    对于测试用例 [0,0,0],修正后的代码能够正确处理,不会再出现索引越界问题,并且能正确返回包含一个三元组 [0,0,0] 的结果列表。

四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n

  • abcd 互不相同

  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

  • 1 <= nums.length <= 200

  • -10(9) <= nums[i] <= 10(9)

  • -10(9) <= target <= 10(9)

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        int a = 0;
        int n = nums.length;
        for (a = 0; a < n - 3; ) {
            int b = a + 1;
            for (int i = b; i < n - 2; ) {
                long t1 = (long)target -nums[a] - nums[i];//防溢出
                //求和为t1
                int left = i + 1;
                int right = n - 1;
                while (left < right) {
                    int sum = nums[left] + nums[right];
                    if (sum > t1) right--;
                    else if (sum < t1) left++;
                    else {
                        res.add(new ArrayList<Integer>(Arrays.asList(nums[a], nums[i], nums[left], nums[right])));
                        left++;
                        right--;
                        //去重1
                        while (left < right && nums[left] == nums[left - 1]) left++;
                        while (left < right && nums[right] == nums[right + 1]) right--;
                    }
                }
                //去重2
                i++;
                while (i < n && nums[i] == nums[i - 1]) i++;
            }
            //去重3
            a++;
            while (a < n && nums[a] == nums[a - 1]) a++;
        }
        return res;
    }
}1
  • 如果遇到:

在这里插入图片描述

表面有溢出,用long t1 = (long)target -nums[a] - nums[i];替换int即可解决

posted @ 2025-10-12 13:08  dearbi  阅读(1)  评论(0)    收藏  举报  来源