leetcode 15/ 16 / 18. 3Sum (Closest), 4Sum

本文深入探讨了寻找数组中三个或四个元素组合,使其和为目标值的算法实现。针对三数之和,介绍了如何通过排序和双指针技巧,高效解决重复元素和性能瓶颈问题。对于四数之和问题,文章提出了类似策略,通过预处理排序和检查边界条件,确保算法的准确性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

给出一个数组,找出所有和为0的三个元素

思路:
可以找出一个元素,剩下的转化为2Sum,但是直接2Sum会TLE
而且有重复的case

所以先把数组排序,容易去重
转化为2Sum时,用两个pointer, 一个从左到右,一个从右到左

和满足0时,去重复元素后left++, right–,以找到所有case
不满足0时,如果<0, left++, 反之right –

//27ms
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        
        if (nums == null || nums.length < 3) {
            return result;
        }
        
        Arrays.sort(nums);
        
        for (int i = 0; i < nums.length - 2; i++) {
            if (i > 0 && 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) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    
                    while (left < right && nums[left] == nums[left+1]) left++;
                    while (left < right && nums[right] == nums[right-1]) right--;
                    
                    left ++;
                    right --;
                } else if (sum < 0) {
                    left ++;
                } else {
                    right --;
                }
            }            
            
        }
        
        return result;
    }

16 . 3 Sum Closest
Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

Example:

Given array nums = [-1, 2, 1, -4], and target = 1.

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

给出一个数组,找出其中3个元素的和,距离target最近。只有一个解

思路:
沿用上面3Sum的方法,只是不需要找出所有的解,遇到Sum=target即返回
同时还是把3Sum排序后转为2Sum,用双指针

//5ms
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int closest = nums[0] + nums[1] + nums[2];
        
        for (int i = 0; i < nums.length - 2; i++) {
            if (i > 0 && 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 (Math.abs(target - closest) > Math.abs(target - sum)) {
                    closest = sum;
                }
                
                if (sum == target) {
                    return target;
                } else if (sum < target) {
                    left ++;
                } else {
                    right --;
                }
            }
        }
        
        return closest;
    }

18 . 4Sum
Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

The solution set must not contain duplicate quadruplets.

Example:

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.

A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

给出一个数组,找出4个元素的和=target,找出所有的解

思路:
仍然是先排序,以去重
找出一个元素,剩下的部分转为3Sum
4Sum的部分要检查重复元素,3Sum中也是检查重复元素

同时左边4个元素的和>target时,证明最小元素的和都不满足,跳出循环
右边4个元素的和<target时,证明最大元素的都不满足,跳出循环

//3ms..
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        
        if (nums == null || nums.length < 4) {
            return result;
        }
        
        Arrays.sort(nums);
        
        for (int i = 0; i < nums.length - 3; i++) {
            if (i > 0 && nums[i] == nums[i-1]) continue;
            
            //most left & most right elements check..
            if (nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) break;
            if (nums[nums.length-1] + nums[nums.length-2] + nums[nums.length-3] 
                + nums[nums.length-4] < target) break;
           
           //to 3Sum..
            for (int next = i + 1; next < nums.length - 2; next ++) {  
                if (next > i+1 && nums[next] == nums[next - 1]) continue;
                
                int left = next + 1;
                int right = nums.length - 1;
            
                if (nums[i] + nums[next] + nums[next+1] + nums[next+2] > target) break;
                if (nums[i] + nums[right] + nums[right-1] + nums[right-2] < target) break;
                
                //similar to 3Sum..
                while (left < right) {
                    int sum = nums[i] + nums[next] + nums[left] + nums[right];
                
                    if (sum == target) {
                        result.add(Arrays.asList(nums[i], nums[next], nums[left], nums[right]));
                    
                        while (left < right && nums[left] == nums[left + 1]) left++;
                        while (left < right && nums[right] == nums[right-1]) right--;
                    
                        left ++;
                        right --;
                    } else if (sum < target) {
                        left ++;
                    } else {
                        right --;
                    }
                }
            }
        
        }
        return result;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值