力扣刷题 之 两数相加&三数相加&四数相加

文章目录

  • 前言
  • 两数相加
    • 题目介绍
    • 思路讲解
    • 代码
      • 暴力法:
      • hash表法:
  • 三数相加
    • 题目介绍
    • 思路讲解
    • 代码
  • 四数相加
    • 题目介绍
    • 思路讲解
    • 代码

前言

一般对于这种数量相加的,我们的思路可以是先对数组进行排序,然后使用双指针的方法

两数相加

力扣第一题,点此跳转

题目介绍

力扣刷题 之 两数相加&三数相加&四数相加_第1张图片

思路讲解

因为是需要返回下标,所以排序双指针有点不合适了。
这里思路有两个:
(1)暴力破解,时间复杂度很高O(N^2 ),未额外创建空间,但时间复杂度过高不推荐
(2)借用hash表,数值和下标以键值对的方式存入,这样时间复杂度小了O(N),创建hash表增加了额外空间,故空间复杂度O(N)

代码

暴力法:

时间复杂度:O(N^2 )
空间复杂度:O(1)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] result = new int[2];
        // 依次遍历
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]+nums[j]==target){
                    result[0]=i;
                    result[1] = j;
                }
            }
        }
        return result;
    }
}

hash表法:

时间复杂度:O(N )
空间复杂度:O(N)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        // 哈希表中的key为数值,value为索引
        Map<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};
            }
            map.put(nums[i],i);
        }
        return new int[0];
    }
}

三数相加

力扣15题-三数之和,点此跳转

题目介绍

力扣刷题 之 两数相加&三数相加&四数相加_第2张图片

思路讲解

1、先对数组进行排序,使用的方法是Arrays.sort(nums);
2、固定第一个数值,后两个数值使用双指针
3、注意的几点:

① 排序后的数组是从小到大的,如果排序后的第一个大于0,直接返回,后边直接不用看了;
② 为了避免重复结果,依次遍历的时候需要判断是否与前一个数相同,上指针也需要判断是否与前/后一个数相同
③ 双指针循环条件left一定要写在前边,写在后边会出现越界的情况

代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        // 需要返回的结果
        List<List<Integer>> result = new ArrayList<>();
        int len = nums.length;
        if(len<3) return result;
        // 对数组进行排序
        Arrays.sort(nums);
        // 开始遍历
        for(int i=0;i<len-2;i++){
            // 如果排序后的第一个数就大于0,直接结束,因为后边的更比0大
            if(nums[i]>0){return result;}
            // 如果当前数和前一个数相等,直接跳过,因为属于重复数组
            if(i>0 && nums[i]==nums[i-1]){continue;}
            // 使用双指针
            int left = i+1;
            int right = len-1;
            while(left < right){
                // 如果符合要求
                if(nums[i]+nums[left]+nums[right]==0){
                    // 将符合条件的添加到列表中
                    result.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    // left需要遍历了,如果left后边的数值一样,left+1略过
                    // 注意,left
                    while(left<right && nums[left]==nums[left+1]){left++;}
                    left++;
                    // right需要遍历了,如果right前边的数值一样,right-1同样略过
                    while(left<right && nums[right]==nums[right-1]){right--;}
                    right--;

                }else if(nums[i]+nums[left]+nums[right]<0){
                    left++;
                }else{
                    right--;
                }
            }
        }
        return result;
    }
}

四数相加

力扣18题-四数之和,点此跳转

题目介绍

力扣刷题 之 两数相加&三数相加&四数相加_第3张图片

思路讲解

看懂了三数相加,那么四数相加就是比三数多了一层遍历
1、排序,这个不用多数了,排序后是从小到大
2、第一层遍历,是确定第一个数:

① 它最最小的三个数相加(即最小值)要是 > 目标值,那么后边一定大,直接结束
② 它与最大的三个数相加(即最大值)要是 < 目标值,那么跳过该轮,直接下一轮,因为最小数需要增加
③ 前两个不符合 即该遍历中 最小值 < 目标值 < 最大值,说明可能会有数能组成目标值,需要遍历了

3、第二层遍历,思路同上边的三数想加了,只不过第二层遍历是从i后边第一个数开始遍历。
(如果代码看不懂,建议多看两遍三数想加的)

代码

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        // 如果nums的长度小于4,直接返回
        List<List<Integer>> result = new ArrayList<>();
        int len = nums.length;
        if(len<4) return result;
        // 对数组进行排序
        Arrays.sort(nums);
        // 遍历第一个数
        for(int i=0;i<len-3;i++){
            // 这里是为了避免重复答案,直接略过
            if(i>0 && nums[i]==nums[i-1]) continue;
            // 如果最小的4个数都比目标值大,那么后边的也不用算了,肯定大
            if((long)nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target) break;
            // 最小的数和最大的三个数想加比目标值小,那么最小的数据需要移动了,直接进入下一轮
            if((long)nums[i]+nums[len-3]+nums[len-2]+nums[len-1]<target) continue;

            // 到这里说明最小的这个数,可以和后边的数组成符合目标值的组合
            // 第二层遍历,先从i后边的依次遍历
            // 其实到这里,就相当于是三数相加了,target-nums[i]就是三数想加的结果了
            for(int j=i+1;j<len-2;j++){
                // 这里又是先判断,用来去除重复答案的
                if(j>i+1 && nums[j]==nums[j-1]) continue;
                // 后边的就跟三数相加一样的思路了,不多解释了
                if((long)nums[i]+nums[j]+nums[j+1]+nums[j+2]>target) break;
                if((long)nums[i]+nums[j]+nums[len-2]+nums[len-1]<target) continue;
                int left = j+1;
                int right = len-1;
                while(left < right){
                    long sum = (long) nums[i]+nums[j]+nums[left]+nums[right];
                    if(sum==target){
                        result.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        while(left<right && nums[left]==nums[left+1]){
                             left++;
                        }
                        left++;
                        while(left<right && nums[right]==nums[right-1]) {
                            right--;
                        }
                        right--;
                    }else if(sum > target){
                        right--;
                    }else{
                        left++;
                    }
                }
            }
        }
        return result;
    }
}

你可能感兴趣的:(力扣刷题,leetcode,算法)