首页 > 代码库 > 【LeetCode】015 3Sum

【LeetCode】015 3Sum

题目:

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

Note: 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]
]

  

题解:

  对于i和j,在j+1至n中寻找符合条件的第三个值,一种方法是建立map映射表,利用map的find函数。对重复项的检测上使用了比较麻烦的方法。

Solution 1 (TLE)

 1 class Solution {
 2 public:
 3     vector<vector<int>> threeSum(vector<int>& nums) {
 4         vector<vector<int>> vv;
 5         vector<int> v;
 6         int i = 0, j = 0, n = nums.size(),tar=0;
 7         unordered_map<int, int> m;
 8         for(; i<n; i++)
 9         //value-position
10             m[nums[i]] = i;
11         for(i=0; i<n-2; i++) {
12             for(j=i+1; j<n-1; j++) {
13                  tar = 0 - nums[i] - nums[j];
14                 if(m.count(tar) && m[tar]>j) {
15                     v.push_back(nums[i]);
16                     v.push_back(nums[j]);
17                     v.push_back(tar);
18                     sort(v.begin(),v.end());
19                     if(find(vv.begin(),vv.end(),v) == vv.end())
20                         vv.push_back(v);
21                         v.clear();
22                 }
23             }
24         }
25         return vv;                
26     }
27 };

  Solution 1 TLE的原因就在于重复字段的判断上,耗费了大量时间。那么怎么降低呢?这里有个小技巧,对于存在可重复数字的数组,往往联想到先将数组排序,这样可能会减少大量工作。于是在for循环前先将nums排序,然后在循环中对于两元素值相同的情况直接跳过,即当nums[i] == nums[i-1]时,由于nums[i-1]已经遍历完成,故跳过nums[i],对于j(尾指针)也是同样的处理。

Solution 2 (312ms)

class Solution {
public:
   vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> vv;
        vector<int> v;
        int i = 0, j = 0, n = nums.size(),tar=0;
        unordered_map<int, int> m;
        sort(nums.begin(),nums.end());
        
        for(; i<n; i++)
        //value-position
            m[nums[i]] = i;
        for(i=0; i<n-2; i++) {
            if (i>0 && nums[i-1]==nums[i]) continue;
            for(j=i+1; j<n-1; j++) {
                if (j>i+1 && nums[j-1]==nums[j]) continue;
                 tar = 0 - nums[i] - nums[j];
                if(m.find(tar) != m.end() && m[tar]>j) {
                    vv.push_back({nums[i],nums[j],tar});
                }
            }
        }
        return vv;                
    }
};

  Solution 2 虽然AC了,但用时312ms,效率太低了。我们进一步进行优化。此题的思路就是在i之后的数组内寻找符合条件的两个值,Solution 1和Solution 2是将i和j固定,寻找第三个值,那么我们也可以固定i,寻找j和k来满足条件。还是先将数组排序,固定i后,j,k分别为剩余数组的头指针、尾指针,在j<k时执行搜索,直到j>=k时停止搜索。遇到重复项依然是跳过处理。

Solution 3  (119ms)

 1 class Solution {
 2 public:
 3     vector<vector<int> > threeSum(vector<int> &nums) {
 4         vector<vector<int>> vv;
 5         sort(nums.begin(), nums.end());
 6         int n = nums.size();
 7 
 8         for(int i=0; i<n-2; i++) {
 9             if(nums[i] > 0) break;
10             if(i>0 && nums[i] == nums[i-1]) continue;
11             int a = nums[i];
12             int j = i+1, k = n-1;
13             while(j<k) {
14                 int b = nums[j], c = nums[k];
15                 if(a+b+c == 0) {
16                     vv.push_back({a,b,c});
17                     while(j<n && nums[j] == nums[j+1]) j++; j++;
18                     while(k>i && nums[k] == nums[k-1]) k--; k--;
19                 }
20                 else if(a+b+c > 0) {
21                     while(k>i && nums[k] == nums[k-1]) k--; k--;
22                 }
23                 else {
24                     while(j<n && nums[j] == nums[j+1]) j++; j++;
25                 }
26             }
27         }
28         return vv;
29     }
30 };

  在重复项检测上也可以利用set的特性:不包含重复项。这只是一个小技巧。

Solution 4 (279ms)

class Solution {
public:
    vector<vector<int> > threeSum(vector<int> &nums) {
        set<vector<int>> sv;
        sort(nums.begin(), nums.end());
        int n = nums.size();

        for(int i=0; i<n-2; i++) {
            if(nums[i] > 0) break;
            int a = nums[i];
            int j = i+1, k = n-1;
            while(j<k) {
                int b = nums[j], c = nums[k];
                if(a+b+c == 0) {
                    sv.push_back({a,b,c});
                    j++;
                    k--;
                }
                else if(a+b+c > 0) k--;
                else j++;
            }
        }
        return vector<vector<int>> (sv.begin(),sv.end());
    }
};

 

【LeetCode】015 3Sum