[Leetcode]Two sum(两数之和)系列总结

Two sum

题目

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
#分析题目

  • 一个数组,还有一个目标数target,让我们找到两个数字,使其和为targe
  • 开启LeetCode刷题的旅程的第一道题目,暴力求解的时间复杂度o(n2),我们优化到线性的时间复杂度来解决问题,那么就是说只能遍历一个数字,那么另一个数字呢,我们可以事先将其存储起来,使用一个HashMap,来建立数字和其坐标位置之间的映射,HashMap是常数级的查找效率,这样,我们在遍历数组的时候,用target减去遍历到的数字,就是另一个需要的数字了,直接在HashMap中查找其是否存在即可,注意要判断查找到的数字不是第一个数字,比如target是4,遍历到了一个2,那么另外一个2不能是之前那个2,先判断是否存在,则避免了这个问题.

代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        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 null;
    }
}

3Sum

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

  • Note:
    Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
    The solution set must not contain duplicate triplets.
  • For example, given array S = {-1 0 1 2 -1 -4},
    A solution set is:
    (-1, 0, 1)
    (-1, -1, 2)

分析题目

  • 本题求三个数的和为0
  • 如果先fix一个数,然后另外的两个数使用Two Sum那种HashMap的解法,但是会有重复结果出现.所以此题并不是考我们Two Sum的解法。
  • 那么我们来分析一下这道题的特点,要我们找出三个数且和为0,那么除了三个数全是0的情况之外,肯定会有负数和正数,我们还是要先fix一个数,然后去找另外两个数,使三个数的和为0.如果能更有效的定位呢?我们肯定不希望遍历所有两个数的组合,所以如果数组是有序的,那么我们就可以用双指针以线性时间复杂度来遍历所有满足题意的两个数组合。
  • 具体做法:
    -1.我们首先对原数组进行排序,然后开始遍历排序后的数组,这里注意不是遍历到最后一个停止,而是到倒数第三个就可以了。
    -2 先做个剪枝优化,就是当遍历到正数的时候就break,因为我们的数组现在是有序的了,如果第一个要fix的数就是正数了,那么后面的数字就都是正数,就永远不会出现和为0的情况了。
    -3 然后我们还要加上重复就跳过的处理,处理方法是从第二个数开始,如果和前面的数字相等,就跳过,因为我们不想把相同的数字fix两次。我们用两个指针分别指向fix数字之后开始的数组首尾两个数,如果与fix的数相加的和current正好为0,则将这两个数和fix的数一起存入结果中。
    -4.然后就是跳过重复数字的步骤了,两个指针都需要检测重复数字。如果current < 0,则我们将左边那个指针j右移一位,使得指向的数字增大一些。同理,如果两数之和大于0,则我们将右边那个指针k左移一位,使得指向的数字减小一些.时间复杂度o(n2).代码如下:
    #代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        for(int i = 0; i < nums.length - 2; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            int j = i + 1, k = nums.length - 1;
            while(j < k) {
                int current = nums[i] + nums[j] + nums[k];
                if (current == 0) {
                    res.add(Arrays.asList(nums[i], nums[j], nums[k]));
                    while(j < k && nums[j] == nums[j + 1]) j++;
                    while(j < k && nums[k] == nums[k - 1]) k--;
                    j++;
                    k--;
                } else if (current < 0) {
                    j++;
                } else {
                    k--;
                } 
            }
        }
        return res;
    }
}

4sum

题目

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)

  • The solution set must not contain duplicate quadruplets.
    For example, given array S = {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)

分析题目

这道题要求跟3Sum差不多,只是需求扩展到四个的数字的和了。我们还是可以按照3Sum中的解法,只是在外面套一层循环,相当于求n次3Sum。我们知道3Sum的时间复杂度是O(n2),所以如果这样解的总时间复杂度是O(n3)。代码如下:

代码

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        int len = nums.length;
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < len - 3; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            for (int j = i + 1; j < len - 2; j++) {
                if (j > 1 && nums[j] == nums[j - 1] && j - i > 1) {
                    continue;
                }               
                int left = j + 1, right = len - 1;
                while (left < right) {
                    int _4sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if (_4sum == target) {
                        res.add(Arrays.asList(nums[i], nums[j], 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 (_4sum > target)
                        right--;
                    else
                        left++;
                }
            }
        }
        return res;
    }
}

你可能感兴趣的:(Leetcode,题解)