数组之2Sum,3Sum,4Sum,3Sum closest总结

来源:互联网 发布:maven 指定java home 编辑:程序博客网 时间:2024/06/06 08:48
数组之two Sum Two Sum描述Given an array of integers, find two numbers such that they add up to a specific target number.The function twoSum should return indices of the two numbers such that they add up to the target,where index1 must be less than index2. Please note that your returned answers (both index1 and index2)are not zero-based.You may assume that each input would have exactly one solution.Input: numbers={2, 7, 11, 15}, target=9  Output: index1=1, index2=2//方法一:暴力枚举法;利用双层循环暴力枚举,空间复杂度为O(1),时间复杂度为O(n^ 2 ),当数组较大时,耗时较长。vector <int> twoSum(vector<int> &numbers,int target){vector<int> results;for(int i=0;i<numbers.size()-1;i++){for(int j=i+1;j<numbers.size();j++){if(numbers[i]+numbers[j]==target){results.push_back(i+1);results.push_back(j+1);}}}return results;} //方法二:先排序,后使用双指针;首先对数组排序,初始时一个指针指向数组第一个元素,另外一个指针指向最后一个元素,如果两数之和大于target,右指针左移,相反,左指针右移。排序时间复杂度为O(N*lg N),查找时间复杂度为O(N),所以整体时间复杂度为O(N*lg N);(以空间换时间)vector<int> twoSum(vector<int> &numbers,int target){vector<int>temp(numbers.size());//新建一个等大数组;vector<int>result;                //用于保存结果;copy(numbers.begin(),numbers.end(),temp.begin());//复制元素;sort(temp.begin(),temp.end());//排序;vector<int>::iterator star=temp.begin();//左指针vector<int>::iterator teminate=temp.end()-1;//右指针while((*start+*teminate)!=target){if((*start+*teminate)>target)teminate--;if((*start+*teminate)<target)start++;}vector<int> iterator a;vector<int> iterator b;if(*start!=*teminate){a=find(numbers.begin(),numbers.end(),*start);b=find(numbers.begin(),numbers.end().*teminate);}else{a=find(numbers.begin(),numbers.end(),*start);b=find(a+1,number.end,*teminate());  //注意起点不同}results.push_back(a-numbers.begin()+1);results.push_back(b-numbers.begin()+1);sort(results.begin(),results.end());return results;}/*方法三、hash表。用一个哈希表,存储每个数对应的下标,复杂度 O(n),空间复杂度 O(n).将逐个比较转变为直接查找,即首先计算出 target与当前元素的差,然后在序列中寻找这个差值,这样首先就把问题简化了,而寻找的过程可以先对序列进行快排,然后二分查找,这样整体的复杂度就降低为 O(N*logN) 了;查找最快的方法是利用一个 map容器存储每个元素的索引,这样取得某个特定元素的索引只需要常数时间即可完成,这样就更快了,最多只需遍历一次序列,将元素及其索引加入map中,在遍历的过程中进行对应差值的查找,如果找到了就结束遍历,这样时间复O(N).vector<int> twoSum(vector<int> &numbers,int target){vector<int> results;map<int,int> hmap;for(int i=0;i<numbers.size();i++){if(!hmap.count(numbers[i]))hmap.insert(pair<int,int>(numbers[i],i));    }for(int i=0;i<numbers.size();i++){const int gap=target-numbers[i];if(hmap.find(gap)!=hmap.end()&&hmap[gap]>i){results.push_back(i+1);results.push_back(hmap[gap]+1);}}return results;}数组之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 triplets in the array which gives the sum of zero.Note:• Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)• 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)方法一:这道题是Two Sum的扩展,暴力枚举时间复杂度为O(n^3), 对每三个数进行比较。这道题和Two Sum有所不同,使用哈希表的                 解法并不是很方便,因为结果数组中元素可能重复,如果不排序对于重复的处理将会比较麻烦 。class solution{public:vector<vector<int>> threeSum(vector<int> &numbers,target){vector<vector<int>> results;int n=numbers.size();if(n<3)  return results;for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){for(int k=j+1;k<n;k++){if(numbers[i]+numbers[j]+numbers[k]==target){vector<int> vi=adjust(numbers[i],numbers[j],numbers[k]);vector<vector<int>> iterator::iter=find(results.begin(),results.end(),vi);if(iter==results.end())results.push_back(vi);           //防止重复}}}}return results;}private:vector<int> adjust(int &a,int &b,int &c)      //条件一约束{if(a>b)swap(a,b);if(a>c){swap(a,c);swap(b,c);}else{if(b>c)swap(b,c);}vector<int>vi;vi.push_back(a);vi.push_back(b);vi.push_back(c);return vi;}}; 方法二:先排序,然后左右夹逼,复杂度 O(n^2 ),空间复杂度 O(1)。这个方法可以推广到 k-sum,先排序,然后做 k − 2 次循环,在最内                层循环左右夹逼,时间复杂度是 O(max{nlogn,n k−1 })。代码一:vector<vector<int>> threeSum(vector<int> &numbers,int target)   {  vector<vector<int>> results;  if(numbers.size()<3)  return results;  sort(numbers.begin(),numbers.end());  for(int i=0;i<numbers.size();i++)  {  if(i>0&&numbers[i]==numbers[i-1])  continue;  // twoSum  int start=i+1;  int end=numbers.size()-1;  int target1=target-numbers[i];  while(start<end)  {  if(start>i+1&&numbers[start]==numbers[start-1])  {  start++;  continue;  }  if(numbers[start]+numbers[end]<target1)  start++;  else if(numbers[start]+numbers[end]>target1)  end--;  else  {  vector<int>triple;  triple.push_back(numbers[i]);  triple.push_back(numbers[start]);  triple.push_back(numbers[end]);  results.push_back(triple);  start++;  }  }  }  return results;   } 代码二:vector<vector<int>> threeSum(vector<int>&nums,int target){vector<vector<int>> results;int len=nums.size();if(len<3)return results;sort(nums.begin(),nums.end());for(int i=0;i<len-2;i++){                     //first number:nums[i];int j=i+1;   //second number;        int k=len-1;  //third number;while(j<k){if(nums[i]+nums[j]+nums[k]<target)j++;else if(nums[i]+nums[j]+nums[k]>target)k--;else{result.push_back({nums[i],nums[j],nums[k]});j++;k--;                              // folowing 3 while can avoid the duplications  while(j<k&&nums[j]==nums[j-1])j++;while(j<k&&nums[k]==nums[k+1])k--;}}while(i<len-2&&nums[i]==nums[i-1])          i++;                                   }   // sort and unique will cost a lot of time and course TLE      // sort(results.begin(), results.end());      // results.erase(unique(results.begin(), results.end()), results.end());return results;                   }//注:unique函数功能是去除相邻的重复元素,注意是相邻,所以必须先使用sort函数,[first,end)。还有一个容易忽视的特性是它并不真正把重复的元素删除。之所以说比不真正把重复的元素删除,因为unique实际上并没有删除任何元素,而是将无重复的元素复制到序列的前段,从而覆盖相邻的重复元素。unique返回的迭代器指向超出无重复的元素范围末端的下一个位置。数组之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)• e solution set must not contain duplicate quadruplets.For example, given array S = {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)//方法一:先排序,然后左右夹逼,时间复杂度 O(n^3),空间复杂度 O(1)代码一:vector<vector<int>> fourSum(vector<int> &nums,int target){vector<vector<int>> results;vector<int> tmp;int len=nums.size();sort(nums.begin(),nums.end());for(int i=0;i<len-3;i++){if(i==0&&nums[i]==nums[i-1])continue;for(int j=i+1;j<len-2;j++){if(j!=i+1&&nums[j]==nums[j-1])continue;int sum=target-nums[i]-nums[j];int left=j+1;int right=len-1;while(left<right){if(nums[left]+nums[right]<sum)left++;else if(nums[left]+nums[right]>sum)right--;else{tmp.clear;tmp.push_back(nums[i]);tmp.push_back(nums[j]);tmp.push_back(nums[left]);tmp.push_back(nums[right]);resultd.push_back(tmp);left++;right--;while(left<right&&nums[left]==nums[left-1])left++;while(left<risht&&nums[right]==nums[right+1])right--;}}}}return results;} 代码二:利用set特性之一set中没有重复元素,即利用set去重;vector<vector<int>> fourSum(vector<int> &nums,int target){vector<vector<int>> results;int len=nums.size();if(len<4)return results;sort(nums.begin(),nums.end());set<vector<int>>tmpres;for(int i=0;i<len-3;i++){for(int j=i+1;j<len-2;j++){int left=j+1;int right=len-1;while(left<right){int sum=nums[i]+nums[j]+nums[left]+nums[right];if(sum==target){vector<int> tmp;tmp.push_back(nums[i]);tmp.push_back(nums[j]);tmp.push_back(nums[left]);tmp.push_back(nums[right]);tmpres.insert(tmp);left++;right--;}else if(sum<target)left++;elseright--;}}}set<vector<int>>::iterator it=tmpres.begin();for(;it!=tmptres.end();it++)results.push_back(*it);return results;} 数组之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 onesolution.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解题 很像,与之不同的是,1、这里不用判断处理重复问题。2、不再是求三个数的和是不是为target,而是看三个数的和与target的差是否为最小,只需记录当前最优解并不断更新其值就可。先排序,然后左右夹逼,时间复杂度 O(n^2),空间复杂度 O(1) vector<vector<int>> threeSumClosest(vector<int> &nums,int target){int len=nums.size();switch (len)          {          case 0:               return 0;          case 1:              return num[0];          case 2:              return num[0] + num[1];          default:              break;          }sort(nums.begin(),nums.end());int results=nums[0]+nums[1]+nums[2];for(int i=0;i<len-3;i++){int j=i+1;int k=len-1;while(j<k){int sum=nums[i]+nums[j]+nums[k];if(abs(results-target)>abs(sum-target))results=sum;else if(sum<target)j++;elsek--;}}return results;} 


0 0
原创粉丝点击