leetcode刷题笔记5——三数和为0、三数和最接近目标数、四数和为目标数

1、三数和为0:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

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

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

#题解:

看评论发现了一个用到指针的算法快速且容易理解,所以在经过理解和自己复写一遍后在此留下笔记。其方法主要是:1、数组从小到大排序;2、循环遍历数组确定三元组中的最小的第一个数nums[i];3、令L=i+1、R=nums.length-1;4、在固定nums[i]的前提下让L和R夹逼,途中把满足条件的三元组添加到lists中;5、遍历途中nums[i+1]==nums[i]则直接跳过,循环直到nums[i]>0结束。

代码: 

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List <List<Integer>> lists=new ArrayList<>();
        Arrays.sort(nums);
        if(nums.length<3) return lists;
        for(int i=0;i<nums.length-2;i++){  //遍历三数的最小数
            int L=i+1;
            int R=nums.length-1;
            if(i>0 && nums[i]==nums[i-1]) continue;
            while(L<R){                   //双指针运动确定剩下两个数
                if(nums[i]>0) return lists;
                int tmp=nums[i]+nums[L]+nums[R];
                if(tmp==0){
                    lists.add(Arrays.asList(nums[i],nums[L],nums[R]));
                    while(L<R && nums[L+1]==nums[L]) L++;
                    while(L<R && nums[R-1]==nums[R]) R--;
                    L++;
                    R--;
                }
                else if(tmp<0)
                    L++;
                else if(tmp>0)
                    R--;
            }
        }
        return lists;
    }
}

2、三数和最接近目标数:

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.

与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

#题解:

用上述指针思路,不过有点暴力不算优:

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        if(nums.length<3) return 0;
        int totarget=999999;
        int Sums=0;
        Arrays.sort(nums);
        //[-1,0,1,1,55]
        for(int i=0;i<nums.length-2;i++){
            int L=i+1;
            int R=nums.length-1;
            while(L<R){
                int sum=nums[i]+nums[L]+nums[R];
                if(Math.abs(sum-target)<totarget){
                    totarget=Math.abs(sum-target);
                    Sums=sum;               
                }
                if(sum==target) return Sums;
                else if(sum<target) L++;
                else if(sum>target) R--; 
            }
        }
        return Sums;
    }
}

3、四数和为目标数:

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

#题解:

此题跟三数和为0是一样的,只是要多一层嵌套循环。三数时只需要把最小数遍历,然后指针移动剩余两数即可。而四数则需要双层嵌套遍历最小的两个数,再把剩下的两个数进行指针移动。注意:如何避免输出重复解是此题最容易出错的地方,我自己提交报错了好几次才完全解决。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List <List<Integer>> result=new ArrayList<>();
        if(nums.length<4 || nums==null) return result;
        Arrays.sort(nums);
        for(int i=0;i<nums.length-3;i++){ //遍历四数中的最小数
            int R=nums.length-1;
            if(nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) break; 
            if(nums[i]+nums[R]+nums[R-1]+nums[R-2]<target) continue;
            if(i>0 && nums[i]==nums[i-1]) continue; //去重复解
            for(int j=i+1;j<nums.length-2;j++){ //遍历第二小的数
                int L=j+1;
                R=nums.length-1;
                if(nums[i]+nums[j]+nums[R-1]+nums[R]<target) continue;
                if(j>i+1 && nums[j]==nums[j-1]) continue;  //去重复解
                while(L<R){  //对剩下的两个数进行左右指针运动
                    if(nums[i]+nums[j]+nums[L]+nums[R]==target){
                        result.add(Arrays.asList(nums[i],nums[j],nums[L],nums[R]));
                        while(L<R && nums[L+1]==nums[L]) L++; //去重复解
                        while(L<R && nums[R-1]==nums[R]) R--;
                        L++;
                        R--;
                    }
                    else if(nums[i]+nums[j]+nums[L]+nums[R]<target) L++;
                    else if(nums[i]+nums[j]+nums[L]+nums[R]>target) R--;
                }
            }
        }
        return result;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值