Leetcode中一维数组与xSum

来源:互联网 发布:utorrent mac 版本 编辑:程序博客网 时间:2024/06/11 05:12

在一维数组总求各种sum的题,大都是通过两个指针从两边走向中间完成。并且前提是数组是有序的。


题目一:Two Sum

Given an array of integers, find two numbers such that they add up to a specific target number.

思路:啥都不说,排个序,while循环两个指针从分别从两头往中间走。

class Solution {public:    vector<int> twoSum(vector<int> &numbers, int target) {        int i=0;        int j=numbers.size()-1;        vector<int> res;        vector<int> copy=numbers;        int first,second;                sort(copy.begin(),copy.end()); //第一步,排序        while(i<j){                    //第二步,从两边往中间走            int sum=copy[i]+copy[j];               if(sum==target){                first=copy[i];                second=copy[j];                break;            }            else if(sum<target) i++;            else j--;        }        for(int i=0;i<numbers.size();i++){ //改变了原始顺序,得额外再搜索一遍            if(res.size()<2){                if(first==numbers[i]) res.push_back(i+1);                else if(second==numbers[i]) res.push_back(i+1);            }        }        return res;    }};
说明:排序的话意味着改变了原始数据,不然的话可以牺牲额外的空间替换。最后需要增加一次额外的遍历,找到相应数据对应的index。还有一中替代方案,就是用map,一方面map是排序的,另一方面,map可以讲排序后的数据和排序前的index关联起来。


题目二:3Sum

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

  • Element in a triplet (a, b, c) must be in non-descending order (ie. a<=b<=c)
  • The solution set must not contain duplicate triplets.
思路:首先第一点,要求triplet有序,很明显要将原始数据(或者备份数据)排序。第二点,去掉重复。所有企图先将重复triplet加进来再去掉都是幻想,我以身试法多次均失败告终,虽然知道是很蠢的方法,但还不让我过。。所以只能在遍历的时候对重复数据进行严格把关了。虽然3Sum比2Sum复杂,但是3Sum要求的只是和为0,那么是不是针对每个负数或0,求一个2Sum算法就OK了呢?貌似可行,但是不行,因为不是所有三元组都是由负数+2个非负数,有可能是2个负数+1一个整数组成,那么这种想法算是失败。失败的原因在于我们只考虑了将负数或者0作为sum,而事实是所有元素都可能成为sum。

class Solution {public:    vector<vector<int> > threeSum(vector<int> &num) {        // IMPORTANT: Please reset any member data you declared, as        // the same Solution instance will be reused for each test case.        typedef vector<int> numbers;        vector<numbers> result;        sort(num.begin(), num.end());        for (int x = num.size()-1; x >=2; x--) { // Do it backwards            if(x < num.size()-1 & num[x] == num[x+1]) continue; // Skip same x            for (int y = 0, z = x-1; y < z;) {                if(y>0 && num[y]==num[y-1]) { // Skip same y                    y++;                    continue;                }                if(z<x-1&&num[z]==num[z+1]) { // Skip same z                    z--;                    continue;                }                int s = num[x] + num[y] + num[z];                if (s > 0)                    z--;                if (s < 0)                    y++;                if (s == 0) {                    vector<int> tmpOne(3);                    tmpOne[0] = num[y];                    tmpOne[1] = num[z];                    tmpOne[2] = num[x];                    result.push_back(tmpOne);                    y++;z--; //因为要找出所有的triplet,所有搜索到这里还不能结束                }            }        }        return result;    }};
说明:代码中对x, y, z的枚举都进行了相应的重复屏蔽操作。代码总共两层循环,第一层循环是对sum可能性的枚举,第二个循环就是上面的2Sum的处理,这里也可以写成一个while循环。因为要找出所有的triplet,所以找到一个结果还得继续循环。


题目三:3Sum Closest

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.  For example, given array S={-1 2 1 -4}, and target=1. The sum that is closest to the target is 2. (-1+2+1=2).

思路:这道题稍微要比上面的3Sum难。但还是需要sort一下。这次不是求确切的值,而是求一个近似解。

class Solution {public:    int threeSumClosest(vector<int> &num, int target) {        double res;        double min=1<<12;                 if(num.size()==0) return 0;        sort(num.begin(), num.end());        for(int k=num.size()-1;k>=2;k--){   //遍历第一个可能取的值int i,j;for(i=0,j=k-1; i<j;){  //2Sum的遍历double tmp_sum=num[i]+num[j]+num[k];double delta=abs(tmp_sum-target);if(delta<min){min=delta;res=tmp_sum;}if(tmp_sum<target) i++;else j--;}}        return (int)res;    }};

题目四:4Sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a+b+c+d=target? find all unique quadruplets in the array which gives the sum of target. Note:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a<=b<=c<=d)
  • The solution set must not contain duplicate quadruplets
思路:这道题的难度比前面的增大了,要枚举四个数。不管枚举几个数,还是得先排序吧。直觉的解法是先枚举前两个,后进行2Sum。这里也要去重复。

class Solution {public:    vector<vector<int> > fourSum(vector<int> &num, int target) {        vector<int> res;        vector<vector<int> > collects;        int i,j;                if(num.size()==0) return collects;        sort(num.begin(), num.end());                for(int k1=num.size()-1;k1>=3;k1--){  //枚举第一个数if(k1<num.size()-1&&num[k1]==num[k1+1])  //过滤掉重复的数continue;for(int k2=k1-1;k2>=2;k2--){  //枚举第二个数if(k2<k1-1&&num[k2]==num[k2+1])  //过滤掉第二个数continue;for(i=0,j=k2-1; i<j;){if(i>0 && num[i]==num[i-1]){i++; continue;}if(j<k2-1 && num[j]==num[j+1]){j--; continue;}int tmp_sum=num[i]+num[j]+num[k1]+num[k2];if(tmp_sum==target){res.push_back(num[i]);res.push_back(num[j]);res.push_back(num[k2]);res.push_back(num[k1]); collects.push_back(res);res.clear();i++;j--;}else if(tmp_sum<target) i++;else j--;}}}        return collects;    }};


下面继续扩大难度,在来一道附加题。


题目五:求和为s的序列

输入一个正整数s, 打印出所有和为s的连续正整数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8.

解析:这次也同样是用两个index,i, j, 不过是另个指针往中间挪动,一个负责序列的头,一个复杂序列的尾部

void findSequenceSum(int sum){      if(sum<3) return;      int i=1;  //第一个index,指向地位      int j=2;  //第二个index,指向高位      int mid=(1+sum)/2;      int curSum=i+j;      while(i<mid){           if(curSum==sum) print(i,j);           while(curSum>sum&&i<mid){curSum-=i;        i++;             if(curSum==sum) print(i,j);           }<span style="white-space:pre"></span>   j++;           curSum+=j;      }}
void findSequenceSum2(int sum){      if(sum<3) return;      int i=1;  //第一个index,指向地位      int j=2;  //第二个index,指向高位      int mid=(1+sum)/2;       int curSum=i+j;      while(i<mid){           if(curSum==sum) print(i,j); //因为要找出所有的序列,故找到之后还得继续循环           if(curSum<=sum){                  j++;                curSum+=j;           }           else{                curSum-=i;                i++;           }      }}
注意,题目2要求找到所有符合要求的序列,故找到一个之后,还得让index继续往前探寻!

总结:(1)如果是求序列的和,用两个指针从左到右,一个负责头部start,一个负责尾部end。如果当前和<target, 则end++, 否则start++. (2)如果求几个数的和,不应定是序列,则用两个指针分别从两边往中间走。(3)总的特点是都需要排序。



0 0
原创粉丝点击