zoukankan      html  css  js  c++  java
  • 15. 3Sum、16. 3Sum Closest和18. 4Sum

    15 3sum

    Given an array nums of n integers, are there elements a, b, c in nums 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.

    Example:

    Given array nums = [-1, 0, 1, 2, -1, -4],
    
    A solution set is:
    [
      [-1, 0, 1],
      [-1, -1, 2]
    ]
    
    思考:1、想了很久,不知道怎么做。只能想到时间复杂度比较高的做法。在网上查到,这个3sum问题是比较经典的,其解法基于2sum。2sum问题是给定一个排好序的数组,问有哪些两个元素相加为
    0。解法是一个下标指向第一个,另一个下标指向最后一个。
    有如下结论及其规则:
    一、如果num[1]+num[n]>0,那么2和n的和大于0,3和n的和也会大于0。等等。所以就没必要再去计算以最后一个为右边界的组合。考虑1,..,n-1这个范围内的组合,即移动后一个。
    二、如果num[1]+num[n]<0,那么1和n-1的和,1和n-2的和也会小于0。等等。所以就没必要去计算以1为左边界的组合。考虑2,...,n这个范围内的组合,即移动前一个下标。
    不断进行这个操作,最终遍历所有可能的组合,而不是每个组合。

    3sum问题可以分解成2sum。取出数组第一个元素X,在剩下的数组里找到两数之和为-X,这就是2sum问题。

    由于c语言不支持动态添加元素,所以用c++可能更方便一些,故实现如下。ps:用c语言做了一下,一直free内存那里出问题。


     1 class Solution {
     2 public:
     3     vector<vector<int>> threeSum(vector<int>& nums) {
     4     vector<vector<int> > ans;
     5     int index1,index2;
     6     if(nums.size()<3) return ans;
     7         
     8     sort(nums.begin(), nums.end());
     9     
    10     for (int i = 0; i <= nums.size()-3; i++) {
    11         if(i!=0 && nums[i-1]==nums[i]) continue;
    12         
    13         index1 = i+1;
    14         index2 = nums.size()-1;
    15         /*if(i==0) {
    16             index1 = 1;
    17             index2 = nums.size()-1;
    18         }
    19         else if (i== nums.size()-1) {
    20             index1 = 0;
    21             index2 = nums.size()-2;
    22         }else {
    23             index1 = 0;
    24             index2 = nums.size()-1;
    25         }*/
    26         
    27         
    28         while(index1<index2) {
    29             if(nums[i]+nums[index1]+nums[index2]==0) {
    30                 int sol[3] = { nums[i], nums[index1], nums[index2] };
    31                 ans.push_back(vector<int> (sol, sol + 3));
    32                 //printf("i is %d.index1 is %d.index2 is %d.
    ", i,index1,index2);
    33                 index1++;while(nums[index1]==nums[index1-1]) index1++;
    34                 index2--;while(nums[index2]==nums[index2+1]) index2--;
    35             }else if (nums[i]+nums[index1]+nums[index2]>0) {
    36                 index2--;
    37             }else {
    38                 index1++;
    39             }
    40         }
    41     }
    42     return ans;
    43     }
    44 };

    16 3sum closet

    Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    Example:

    Given array nums = [-1, 2, 1, -4], and target = 1.
    
    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
    

    和上面是简单变形关系,所用的原理一样。因为此次并不需要返回数组的数组,所以又用c语言来表示我的行为。

     1 void my_qsort(int *nums, int index1, int index2) {
     2     if(index1==index2) return;
     3     
     4     int pre,last;
     5     int tmp;
     6     
     7     pre = index1;
     8     for(last=index1+1; last<=index2; last++) {
     9         if(nums[last]<nums[index1]) {
    10             pre++;
    11             tmp = nums[pre];
    12             nums[pre] = nums[last];
    13             nums[last] = tmp;
    14         }
    15     }
    16     tmp = nums[index1];
    17     nums[index1] = nums[pre];
    18     nums[pre] = tmp;
    19     
    20     if(pre==index1) {
    21         my_qsort(nums, index1+1, index2);
    22     }else if(pre==index2) {
    23         my_qsort(nums, index1, index2-1);
    24     }else {
    25         my_qsort(nums, index1, pre-1);
    26         my_qsort(nums, pre+1, index2);
    27     }
    28     
    29 }
    30 
    31 int threeSumClosest(int* nums, int numsSize, int target) {
    32    int ret,index1,index2,tmp;
    33     my_qsort(nums, 0, numsSize-1);
    34     for(int i = 0; i<numsSize; i++)
    35         printf("%d ", nums[i]);
    36     printf("
    ");
    37     ret = nums[0] + nums[1] + nums[2];
    38     for(int i=0; i<=numsSize-3;i++) {
    39         index1 = i+1;
    40         index2 = numsSize-1;
    41         while(index1<index2) {
    42            tmp = nums[i] + nums[index1] + nums[index2];
    43             if(tmp == target) return tmp;
    44             if(abs(tmp-target)<abs(ret-target)) ret = tmp;
    45             if(tmp>target) {
    46                 index2--;
    47             }else if(tmp < target) {
    48                 index1++;
    49             }
    50         }
    51     }
    52     
    53     return ret;
    54 }

    18. 4Sum

    Given an array nums of n integers and an integer target, are there elements a, b, c, 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]
    ]
    
    思考:首先按一定顺序取前两个数,共有(n-3)*(n-2)个组合,对于剩下的两个数就用首尾指针进行移动检查。
    这里我有一个小小的优化。看下line 12行的代码,如果nums[i]大于0,nums[i]>terget,那么后面的三个数一定大于0。既然后面的三个数都大于0,nums[i]加上大于的0
      一定大于target。所以就没有必要再继续检查。第15行代码同理。
      
     1 class Solution {
     2 public:
     3     vector<vector<int>> fourSum(vector<int>& nums, int target) {
     4         vector<vector<int>> ans;
     5         
     6         sort(nums.begin(), nums.end());
     7         
     8         int len = nums.size();
     9         int i,j,k,l;
    10         
    11         for(i=0; i<=len-4; i++) {
    12             if(nums[i]>target && nums[i]>=0) continue;
    13             if(i>=1 && nums[i]==nums[i-1]) continue;
    14             for(j=i+1; j<=len-3; j++) {
    15                 if(nums[i]+nums[j]>target && nums[j]>=0) continue;
    16                 if(j>=i+2 && nums[j]==nums[j-1]) continue;
    17                 k = j + 1;
    18                 l = len - 1;
    19                 while(k<l) {
    20                     if(nums[i]+nums[j]+nums[k]+nums[l]>target) {
    21                         l--;
    22                     }else if(nums[i]+nums[j]+nums[k]+nums[l]<target){
    23                         k++;
    24                     }else {
    25                         int sol[4] = { nums[i], nums[j], nums[k],nums[l] };
    26                         ans.push_back(vector<int> (sol, sol + 4));
    27                         k++;
    28                         while(nums[k]==nums[k-1]) k++;
    29                         l--;
    30                         while(nums[l]==nums[l+1]) l--;
    31                     }
    32                         
    33                 }
    34                 
    35             }  
    36         }
    37         return ans;
    38     }
    39 };
  • 相关阅读:
    Asp.net_解决vs运行报在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题的bug方法
    WebConfig常用节点
    编译器错误消息:必须添加对程序集“System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”的引用
    使用Log4net调试NHibernate
    Visual Studio 2012 如何打开MVC1.0 MVC2.0的项目
    MVC中IQueryable与IList的区别?
    vs2010 打开 vs2012 的解决方案
    LINQ分页和排序,skip和Take 用法
    未找到与约束ContractName Microsoft.VisualStudio.Text.ITextDocumentFactoryService
    在Sql server数据库中,关于触发器的创建、调用及删除
  • 原文地址:https://www.cnblogs.com/midhillzhou/p/8824055.html
Copyright © 2011-2022 走看看