zoukankan      html  css  js  c++  java
  • 【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.insert({a,b,c});
                        j++;
                        k--;
                    }
                    else if(a+b+c > 0) k--;
                    else j++;
                }
            }
            return vector<vector<int>> (sv.begin(),sv.end());
        }
    };
  • 相关阅读:
    Linux系统安装IonCube的方法详解教程
    CentOS7 安装 odoo10
    关于WPF的弹出窗口
    WPF命令使用
    WPF访问UserControl的自定义属性和事件
    一步步实现 Prism + MEF(二)--- 绑定命令
    一步步实现 Prism + MEF(一)--- 搭建框架
    MVVM里绑定TreeView控件的SelectedItem
    MAF框架的使用限制
    排序--归并排序算法
  • 原文地址:https://www.cnblogs.com/Atanisi/p/6714303.html
Copyright © 2011-2022 走看看