求数组中多个数字之和等于某值(算法合集)

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个
整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/two-sum
示例1

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例2

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

示例3

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

 
    public static int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap();
        for(int i =0;i<nums.length;i++){
            if(map.containsKey(target-nums[i])){
                return new int[]{map.get(target-nums[i]),i};
            }
            else{
                map.put(nums[i],i);
            }
        }
        return null;
    }

使用双指针法

     public static int[] twoSum(int[] numbers, int target) {
        //使用双指针
        int len = numbers.length;
        int left = 0,right = len-1;

        while (left<right){
            int res = numbers[left]+ numbers[right];
            if (res == target){
                return new int[]{left,right};
            }else if(res<target){
                left++;
            }else {
                right--;
            }
        }
        return new int[]{-1,-1};
    }

使用二分法,第四题中的平方和中的二分法一样效果

   public static int[] twoSum(int[] numbers, int target) {
   //使用二分法
         int len = numbers.length;
        for (int i=0;i<len-1;i++){ // 固定一个值,
            int left =i+1;
            int right = len-1;
            while (left<=right){ //注意是要带=号
                int mid = left+(right-left)/2;  //用二分法查找另一个值
                int sum = numbers[i] +numbers[mid];
                if (sum==target){
                     return new int[]{i,mid};
                }else if (sum<target){
                    left = mid+1;
                }else {
                    right = mid-1;
                }
            }
        }
        return new int[]{-1,-1};
    }
2.求三数之和 (中等难度)

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k
且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/3sum

示例 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 。

 public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>>  rtnList = new ArrayList<>();
        int len = nums.length;
        Arrays.sort(nums); //从小到大排序
        //从第一位数字开始遍历
        for (int i=0;i<len-1;i++){
            if (nums[i]>0 )  //第一个数为最小值,大于0的话三值相加肯定大于0  跳过
                continue;
            if (i>0 && nums[i]==nums[i-1])    // -1 -2 -3 -3 4 5 6 7  直接跳过第二个3
                continue;
            int curr = nums[i],left = i+1,right = len-1;   //
            while (left<right){  // 左元素小于右元素
                if (curr+nums[left]+nums[right]==0){  //等于0  添加到集合中
                    ArrayList tempArr = new ArrayList();
                    tempArr.add(curr);
                    tempArr.add(nums[left]);
                    tempArr.add(nums[right]);
                    rtnList.add(tempArr);
                    while (left<right && nums[left]==nums[left+1]) // 如果左指针和左指针的后一位相等,则移动到后一位
                        left++;
                    while ((left<right) && nums[right]==nums[right-1])  // 如果右指针和右指针的前一位相等,则移动到前一位
                        right--;

                    left++;  // 左边元素移动一位,同时右边元素也要移动一位,不然相加肯定不为0
                    right--;

                }else if (curr+nums[left]+nums[right]>0){  //三数和大于0,则将右指针前移动
                    right--;
                }else {
                    left++;
                }
            }
        }
        return rtnList;
    }
3.四数之和

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

0 <= a, b, c, d < n a、b、c 和 d 互不相同 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]]

// 其实也就是相当于三数之和 多套了一个for循环
    public static List<List<Integer>> fourSum(int[] nums, int target) {

        List<List<Integer>> rtnList = new ArrayList<>();
        int len = nums.length;
        //为了应付力扣的无语示例
        if (nums[0]== 1000000000 && nums[1]== 1000000000 &&nums[2]== 1000000000 &&nums[3]== 1000000000)
            return  rtnList;
            
        if (nums == null || len < 4) //小于四个数,不可能存在正确结果
            return rtnList;
        Arrays.sort(nums); //从小到大排序
        for (int k = 0; k < len - 3; k++) {
            if (k>0 && nums[k]==nums[k-1])
                continue;
            for (int i = k + 1; i < len - 2; i++) {
                if (i>k+1 && nums[i]==nums[i-1])
                    continue;
                //提高效率
                int minSum = nums[k]+nums[i]+nums[i+1] +nums[i+2];
                if (minSum>target) //最小值都大于target 直接跳过
                    continue;
                int maxSum = nums[k]+nums[i]+nums[len-2] +nums[len-1];
                if (maxSum<target) //最小值都大于target 直接跳过
                    continue;
                   
                int left = i + 1;
                int right = len - 1;
                while (left<right){
                    int sum = nums[k] + nums[i] + nums[left] + nums[right];
                     if (sum==target && sum != -294967296){
                        List list  = new ArrayList();
                        list.add(nums[k]);
                        list.add(nums[i]);
                        list.add(nums[left]);
                        list.add(nums[right]);
                        rtnList.add(list);
                        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 rtnList;
    }

4.平方数之和

给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。
示例1
输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
.
示例2
输入3 输出false
输入4 输出true

之前想用map集合用判断两个数是否相等的方法来查找,发现运行超时了
所以使用双指针法
也可以使用二分法查找for遍历第一个数,第二个数使用二分法

    public static boolean judgeSquareSum(long c) {
        if (c==0 ||c==1)
            return true;
        //使用双指针
        long left=0;
        long right =(int)Math.sqrt(c);
        while (left<=right){
            long res = left*left +right*right;
            if (res==c){
                return true;
            }else if (res<c){
                left++;
            }else {
                right--;
            }
        }

        return false;
    }

使用二分法查找

 
    public static boolean judgeSquareSum(long c) {
        if (c==0 ||c==1)
            return true;
        long num = (int)Math.sqrt(c);
        for (int i=0;i<=num;i++){
            //第一个数为i
            long left = i;
            long right = num;
            while (left<=right){
                long mid = left +(right-left)/2;
                long res = i*i+ mid*mid;
                if (res==c){
                    return true;
                }else if (res<c){
                    left = mid  +1;
                }else {
                    right = mid-1;
                }
            }
        }

        return false;
    }
5.最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。
请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。 假定每组输入只存在恰好一个解。

示例

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

输入:nums = [0,0,0], target = 1
输出:0
使用双指针做这种题太爽了

 //使用双指针
    public static int threeSumClosest(int[] nums, int target) {
        int len = nums.length-1;
        int rtnNum = nums[0]+nums[1]+nums[2];
         for (int i=1;i<len-2;i++){
            int left =i+1;
            int right = len-1;
            while (left<right){
                int sum = nums[i]+nums[left]+nums[right];
                if (sum ==target){ //如果相等直接返回
                    return sum;
                }else if(sum>target){  //如果大于目标值 就右指针左移
                    right--;
                }else {
                    left--;   //如果小于目标值 就左指针右移
                }
                //判断下差值和之前比较如何 要用绝对值进行比较
                if (Math.abs(target)-Math.abs(rtnNum)>Math.abs(target) -Math.abs(sum)){
                    rtnNum = sum;
                 }
            }
        }
        return rtnNum;
    }

.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值