leetcode-四数之和

 题目来自LeetCode,链接:4sum。具体描述为:给定一个包含 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]
]

 这与之前一篇博客的三数之和很相似(没看的话需要先看一下),无非就是多了一层循环,之前用三个指针那这里就用四个指针罢了。

 同样,首先对数组排序。然后初始化四个指针–first,second,third和fourth,让first遍历0到数组倒数第4个数,second遍历first+1到数组倒数第3个数,然后third就位于second+1,fourth就位于数组最后,让third和fourth进行相向运动(类似于三数之和的left和right)来寻找符合条件的四元组。具体描述如下:

  • 假设L为数组长度,遍历first从0到L-3;
    • 遍历second从first+1到L-2;
      • 初始化third=second+1,fourth=L-1,计算四个数之和;
      • 如果四数之和=target,找到一个符合条件的四元组,third右移到不同的另一个数上去,fourth左移到不同的另一个数上去;
      • 如果四数之和
      • 否则即四数之和>target,说明需要减少,所以fourth左移。
    • 在不超过L-2的情况下右移second到不同的另一个数上去
  • 在不超过L-3的情况下右移first到不同的另一个数上去

 这样虽然可以AC,但是会发现时间消耗还比较久,若想减少时间需要做一些判断:

  • 若当前可能的四数之和最小值已经大于target,可以判定接下来不会再有符合条件的了,可以直接break;
  • 若当前可能的四数之和最大值已经小于target,这时需要增大数,直接continue跳过当前的数。

 可以看到这种方法的时间复杂度为 O ( n 3 ) O(n^{3}) O(n3)

 JAVA版代码如下:

class Solution {
    public List> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        List> result = new ArrayList<>();
        int numsLen = nums.length;
        int first = 0;
        while (first < numsLen - 3) {
            int second = first + 1;
            if (nums[first] + nums[first+1] + nums[first+2] + nums[first+3] > target) {
                break;
            }
            if (nums[first] + nums[numsLen-3] + nums[numsLen-2] + nums[numsLen-1] < target) {
                ++first;
                while (first < numsLen - 3 && nums[first] == nums[first - 1]) {
                    ++first;
                }
                continue;
            }
            while (second < numsLen - 2) {
                if (nums[first] + nums[second] + nums[second+1] + nums[second+2] > target) {
                    break;
                }
                if (nums[first] + nums[second] + nums[numsLen-2] + nums[numsLen-1] < target) {
                    ++second;
                    while (second < numsLen - 2 && nums[second] == nums[second - 1]) {
                        ++second;
                    }
                    continue;
                }
                int third = second + 1;
                int fourth = numsLen - 1;
                while (third < fourth) {
                    int sum4num = nums[first] + nums[second] + nums[third] + nums[fourth];
                    if (sum4num == target) {
                        result.add(Arrays.asList(nums[first], nums[second], nums[third], nums[fourth]));
                        ++third;
                        while (third < fourth && nums[third] == nums[third - 1]) {
                            ++third;
                        }
                        --fourth;
                        while (fourth > third && nums[fourth] == nums[fourth + 1]) {
                            --fourth;
                        }
                    }
                    else if (sum4num < target) {
                        ++third;
                        while (third < fourth && nums[third] == nums[third - 1]) {
                            ++third;
                        }
                    }
                    else {
                        --fourth;
                        while (fourth > third && nums[fourth] == nums[fourth + 1]) {
                            --fourth;
                        }
                    }
                }
                ++second;
                while (second < numsLen - 2 && nums[second] == nums[second - 1]) {
                    ++second;
                }
            }
            ++first;
            while (first < numsLen - 3 && nums[first] == nums[first - 1]) {
                ++first;
            }
        }
        return result;
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        length = len(nums)
        result = []
        nums.sort()                                             #先排序
        first = 0
        while first < length - 3:                               #第一个数最右的位置也只能到倒数第四
            second = first + 1
            if sum(nums[first : first + 4]) > target:           #最小值已经大于target,可以结束
                return result
            if nums[first] + sum(nums[length - 3 : length]) < target:
                first += 1
                while first < length - 3 and nums[first] == nums[first - 1]:
                    first += 1                                  #将第一个数的索引移动到下一个不一样的数上
                continue                                        #最大值已经小于target,必须再增大第一个数
            while second < length - 2:                          #第二个数最右的位置也只能到倒数第三
                if nums[first] + sum(nums[second : second + 3]) > target:
                    break                                       #最小值已经大于target,跳出第二层循环
                if nums[first] + nums[second] + sum(nums[length - 2 : length]) < target:
                    second += 1
                    while second < length - 2 and nums[second] == nums[second - 1]:
                        second += 1                             #将第二个数的索引移动到下一个不一样的数上
                    continue                                    #最大值小于target,必须再增大第二个数
                third = second + 1
                fourth = length - 1
                sum12 = nums[first] + nums[second]
                while third < fourth:
                    sum4num = sum12 + nums[third] + nums[fourth]
                    if sum4num == target:                       #如果四个数之和刚好等于目标值,加入结果list
                        result.append([nums[first], nums[second], nums[third], nums[fourth]]);
                        third += 1 
                        while third < fourth and nums[third] == nums[third - 1]:
                            third += 1                          #将第三个数的索引移动下一个不一样的数上去
                        fourth -= 1
                        while fourth > third and nums[fourth] == nums[fourth + 1]:
                            fourth -= 1                         #将第四个数的索引移动下一个不一样的数上去
                    elif sum4num < target :                     #当四个数之和小于目标值,第三个数的索引右移到一个不同的数上
                        third += 1
                        while third < fourth and nums[third] == nums[third - 1]:
                            third += 1
                    else:                                       #当四个数之和大于目标值,第四个数的索引左移到一个不同的数上
                        fourth -=1
                        while fourth > third and nums[fourth] == nums[fourth + 1]:
                            fourth -= 1
                second += 1
                while second < length - 2 and nums[second] == nums[second - 1]:
                    second += 1                                 #将第二个数的索引移动到下一个不一样的数上
            first += 1
            while first < length - 3 and nums[first] == nums[first - 1]:
                first += 1                                      #将第一个数的索引移动到下一个不一样的数上
        return result

 提交结果如下:


你可能感兴趣的:(LeetCode)