[Java 算法] 双指针 2

双指针解决多数之和问题

1.LCR 179. 查找总价格为目标值的两个商品

class Solution {
    public int[] twoSum(int[] price, int target) {
        int left = 0, 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};
    }
}

利用排好序这个方面 , 使用双指针 , 每次循环都求一次和 , 如果这个 和大于 target , 只需让 right-- ; 如果这个和小于target , 只需让 left++

2.三数之和

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> listall = new ArrayList<>();
        Arrays.sort(nums);
        for(int i = 0;i<nums.length;i++){
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int left = i+1;
            int right = nums.length-1;

            while(left<right&&left<nums.length&&right>i){
                int sum = nums[left] + nums[right]+nums[i];
                if(sum>0){
                    right--;
                }else if(sum<0){
                    left++;
                }else{
                    List<Integer> list1 = new ArrayList<>();
                    list1.add(nums[left]);
                    list1.add(nums[right]);
                    list1.add(nums[i]);
                    listall.add(list1);

                    while((left<right&&nums[right] == nums[right-1])){
                        right--;
                    }
                    while((left<right&&nums[left] == nums[left+1])){
                        left++;

                    }
                    right--;
                    left++;
                }
            }

            
        }
        return listall;
    }
}

核心操作 :

  • 排序 : 先对数组排序 , 方便为后续去重和双指针移动
  • 固定一个元素+双指针找另外两个元素 :
    • 外层循环固定第一个元素 nums[i]
    • 内层用双指针(left = i+1 , right = 数组末尾)寻找另外两个数 , 使得三数之和为 0
  • 去重 : 跳过重复元素 , 避免结果集中出现重复的三元组

注意 :

  • 去重细节:当找到一个有效三元组后,需跳过与当前 left/right 相同的元素(如 nums[left] == nums[left+1]left++),否则会产生重复结果去重后需同时移动 leftrightleft++right--),因为单个移动会导致重复计算
  • 不漏 : 找到一种结果之后 , 不要停止 , 接着缩小区间继续寻找

3.四数之和

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> listAll = new ArrayList<>();
        Arrays.sort(nums);

        for (int i = 0; i < nums.length; i++) {

            if (i > 0 && nums[i - 1] == nums[i]) {
                continue;
            }
            for (int j = i + 1; j < nums.length; j++) {
                if (j > i+1 && nums[j - 1] == nums[j]) {
                    continue;
                }
                int left = j + 1;
                int right = nums.length - 1;

                while (left < right && left < nums.length && right > j) {
                long sum = (long)nums[left] + nums[right] + nums[j] + nums[i];//防止越界
                    if (sum > target) {
                        right--;
                    } else if (sum < target) {
                        left++;
                    } else {
                        List<Integer> list1 = new ArrayList<>();
                        list1.add(nums[left]);
                        list1.add(nums[right]);
                        list1.add(nums[i]);
                        list1.add(nums[j]);
                        listAll.add(list1);

                        while ((left < right && nums[right] == nums[right - 1])) {
                            right--;
                        }
                        while ((left < right && nums[left] == nums[left + 1])) {
                            left++;

                        }
                        right--;
                        left++;
                    }
                }
            }
        }
        return listAll;
    }
}

核心思路 :

  • 排序 : 先对数组排序 , 方便后续去重和双指针移动
  • 固定两个元素 : 通过两层嵌套循环 , 固定四元组中的前两个元素 num[i] 和 num[j](i<j)
  • 双指针找剩余两个元素 : 再固定前两个元素后 , 用双指针(left = j+1 , right = 数组末尾) 寻找另外两个元素 , 使得四数之和为 target
  • 去重 : 跳过重复元素 , 避免结果集中出现重复的三元组

注意 :

  • 不漏 : 找到一种结果之后 , 不要停止 , 接着缩小区间继续寻找
  • 整数有溢出的风险改用 long 类型计算
  • 去重细节:找到有效四元组后,需跳过与当前 left/right 相同的元素(如 nums[left] == nums[left+1]left++),否则会产生重复结果 ; 去重后同时移动 leftright,避免重复计算

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值