LeetCode_Medium_18. 4Sum

2019.1.29

题目描述:

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

Note:

The solution set must not contain duplicate quadruplets.

Example:

Given array nums = [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]
]

这题算是求三数之和的升级版,变成了求四数之和,不过思想上基本上还是一样的,先固定前两个数,再线性遍历后两个数取和即可,也就是多了一层循环而已。因为要求返回不重复的数组,所以这里我们使用C++中STL的set来去重。

解法一:用set去重

C++代码:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        set<vector<int>> res;
        int temp;
        sort(nums.begin(),nums.end());
        for(int i=0;i<int(nums.size()-3);i++){
            for(int j=i+1;j<int(nums.size()-2);j++){
                if(j>i+1&&nums[j]==nums[j-1]) continue;
                int m=j+1,n=nums.size()-1;
                while(m<n){
                    temp=nums[i]+nums[j]+nums[m]+nums[n];
                    if(temp==target){
                        vector<int> out={nums[i], nums[j], nums[m], nums[n]};
                        res.insert(out);
                        m++;n--;
                    }else if(temp<target)m++;
                    else n--;
                }
            }
        }
         return vector<vector<int>>(res.begin(), res.end());
    }
};

时间复杂度:O(n^3)

有几个要注意的点:

1.我们用set去重,但是最后需要返回vector<vector<int>>类型。

2.开始我在i,j的范围用的是nums.size()-3,nums.size()-2,但是有个测试用例没有通过,即输入为[ ]时,后来几经查阅,终于明白了,因为nums.size()是unsigned int,当nums.size()为0时,nums.size()-2就为2^32-2,循环次数太多了,直接超了。

 

 

看评论有不用set直接手动去重的,我就直接贴一下吧。

解法二:手动去重
C++代码:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int> &nums, int target) {
        vector<vector<int>> res;
        int n = nums.size();
        sort(nums.begin(), nums.end());
        for (int i = 0; i < n - 3; ++i) {
            if (i > 0 && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < n - 2; ++j) {
                if (j > i + 1 && nums[j] == nums[j - 1]) continue;
                int left = j + 1, right = n - 1;
                while (left < right) {
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        vector<int> out{nums[i], nums[j], nums[left], nums[right]};
                        res.push_back(out);
                        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 res;
    }
};

时间复杂度:O(n^3)

 

Follow Up:

评论里直接贴出了kSum的代码,我看了,挺好的,直接贴出了吧,这类题目思想还是一样的。

C#代码:

public class Solution 
{
    private int _len;

    public IList<IList<int>> FourSum(int[] nums, int target) {
        _len = nums.Length;
        nums = nums.OrderBy(n => n).ToArray();
        return KSum(nums, target, 4, 0);
    }
    
    private IList<IList<int>> KSum(int[] nums, int target, int k, int index)
    {
        var res = new List<IList<int>>();

        if (index >= _len) return res;

        if (k == 2)
        {
            int i = index, j = _len - 1;
            while (i < j)
            {
                // Find a pair
                if (target - nums[i] == nums[j])
                {
                    res.Add(new List<int> { nums[i], target - nums[i] });

                    // Skip duplication
                    while (i < j && nums[i] == nums[i + 1]) i++;
                    while (i < j && nums[j - 1] == nums[j]) j--;
                    i++;
                    j--;
                }
                // Move left bound
                else if (target - nums[i] > nums[j]) i++;
                // Move right bound
                else j--;
            }
        }
        else
        {
            for (var i = index; i < _len - k + 1; i++)
            {
                // Use current number to reduce K Sum into K-1 Sum
                var temp = KSum(nums, target - nums[i], k - 1, i + 1);
                if (temp.Any())
                {
                    // Add previous results
                    foreach (var t in temp)
                    {
                        t.Add(nums[i]);
                    }
                    res.AddRange(temp);
                }

                // Skip duplicated numbers
                while (i < _len - 1 && nums[i] == nums[i + 1]) i++;
            }

        }

        return res;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值