题目介绍
算法设计
第一阶段
三重for循环,从前到后遍历所有情况,时间复杂度为O(n^3)。
vector< vector<int> > threeSum(vector<int>& nums){
vector< vector<int> >sum;
vector<int>temp(3);
int x = 0;
int num1,num2,num3;
for(int i = 0;i < nums.size()-2;i++){
num1 = nums[i];
for(int j = i+1;j < nums.size()-1;j++){
num2 = nums[j];
for(int k = j+1;k < nums.size();k++){
num3 = nums[k];
if(num1+num2+num3 == 0){
temp[0] = num1;
temp[1] = num2;
temp[2] = num3;
sum.push_back(temp);
}
}
}
}
return sum;
}
这种算法过于基础直接采用遍历进行问题求解,主要存在一下两个问题:
- 时间复杂度达到了O(n^3),计算量太大
- 无法避免题目中重复数组的问题,只能通过进行处理。基本处理步骤如下:
- 对每个三元组进行排序,sort或者set,时间复杂度为O(1)
- 用两重for循环进行删重,时间复杂度为O(n^2)
第二阶段
我上周在leetcode上做到的一道题给了我启发。题目是:给定一个有序数组,求出和为0的所有二元组,二元组不可相同。
上一题为了解决二元组相同重复,设置了两个指针一头一尾,一个从前往后走,一个从后往前走,避免了数组相同的问题。
其时间复杂度为O(n/2);
其代码实现如下:
vector< vector<int> > TwoSum(vector<int>& nums){
vector< vector<int> >sum;
vector<int>temp(2);
int x = 0;
int num1,num2;
sort(nums.begin(),nums.end());
int i = 0;
int j = nums.size()-1;
while(i< j){
if(nums[i] + nums[j] == 0){
temp[0] = nums[i];
temp[1] = nums[j];
sum.push_back(temp);
}
i++;
j--;
}
return sum;
}
在第一阶段三重循环基础上改进,a+b+c = 0这个等式可以改进为a+b = -c;即外循环将c固定,内循环利用TowSum()函数寻找和为-c的二元组,拼在一起即可。这样此种算法的时间复杂度仅为O(n^2),且无需后去去重操作。修改后的代码为,其总代码只有20行,十分简单。
vector< vector<int> > ThreeSum(vector<int>& nums){
vector< vector<int> >sum(0,vector<int>(3));
vector<int>temp(3);
int x = 0;
sort(nums.begin(),nums.end());
for(int k = 0;k < nums.size()-2;k++){
temp[0] = nums[k];
int i = k+1;
int j = nums.size()-1;
while(i < j ){
if(nums[i] + nums[j] == 0-nums[k]){
temp[1] = nums[i];
temp[2] = nums[j];
sum.push_back(temp);
}
i++;
j--;
}
}
return sum;
}
一些坑
在写内层循环时判断是否存在和为-c的二元组时,在两个下标i,j的边缘条件时,我们实在无需考虑得太复杂无需考虑数组长度奇数或偶数的情况分开讨论,只需保证从前往后走的下标始终在从后往前走的下标前即可,即简单的i < j即可。下面是错误的示范:
while((i + ((nums.size()-1)%2)) != j){