首次使用LeetCode学习算法设计,希望通过本次学习可以提高自己对各种算法的了解。
本次选择的题目是15.3Sum,属于medium难度。该题目的描述是"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: The solution set must not contain duplicate triplets."也就是说,给定一个有n个整数的数组S,在S中,是否能找到a,b和c三个数,使得a+b+c=0成立?找出所有唯一的三元组。注意的是,结果集不能包含重复的三元组。举个例子:
给定数组 S = [-1, 0, 1, 2, -1, -4]
结果集是:
[
[-1, 0, 1],
[-1, -1, 2]
]
本题目的思路与Two Sum类似,将-a作为目标值,在数组S中找到两个数相加正好等于-a即可。按照这种想法,通过三层循环可以找到结果的元组,为了避免重复,首先对数组S进行排序,接着循环,然后使用unique函数使得vector中的元素唯一。然而,这种暴力的做法会导致超时。因此,需要其他的方法来替代unique函数。
在对数组S进行排序后,相同的整数排在一起。因此,我的思路是在最外层的每次循环(假设循环量是k)后,都要判断S[k+1]是否和S[k]一样,可以防止出现重复。如上面例子数组排序后是S = [-4, -1, -1, 0, 1, 2],当S[k] = -1,即a=-1时,找到b和c相加等于1,即0和1;在选择S[k+1]前,发现S[k+1]和S[k]相同,必然会出现同样一个三元组,因此直接跳过S[k+1]即可避免重复。同理,对于找到数b和数c的循环,也需要进行同样的判断。代码如下。
for(int k = 0; k < nums.size(); k ++){
int target = 0 - nums[k];
int rest = 0;
i = k+1;
for (; i < nums.size();i ++)
{
rest = target - nums[i];
for (j = i+1; j < nums.size(); j ++)
{
if (rest == nums[j])
{
vector<int> vec;
vec.push_back(nums[k]);
vec.push_back(nums[i]);
vec.push_back(nums[j]);
res.push_back(vec);
}
while ((j + 1 < nums.size()) && (nums[j] == nums[j+1]))
j ++;
}
while ((i + 1 < nums.size()) && (nums[i] == nums[i+1]))
i ++;
}
while ((k + 1 < nums.size()) && (nums[k] == nums[k+1]))
k ++;
}
然而,这种做法没有使用unique函数,但是循环多了,还是会超时。所以根据提示使用两个指针的话,那么考虑数b和数c的查找分别从前和后两个位置开始找。b首先取得是S[k+1]的值,c首先取的是S[S.size()-1]的值,按照b+c的大小,移动两个循环变量i和j。若发现相等,则记录到vector中,同时,处理b和c可能重复的部分。代码如下所示。结果不会超时。
vector<vector<int> > threeSum(vector<int>& nums) {
vector<vector<int> > res;
sort(nums.begin(),nums.end());
for(int k = 0; k < nums.size(); k ++){
int target = 0 - nums[k];
int i = k+1;
int j = nums.size() -1;
while (i < j)
{
if(nums[i] + nums[j] < target)
i ++;
else if(nums[i] + nums[j] > target)
j --;
else {
vector<int> vec;
vec.push_back(nums[k]);
vec.push_back(nums[i]);
vec.push_back(nums[j]);
res.push_back(vec);
while ((i < j) && (nums[i] == vec[1]))
i ++;
while ((i < j) && (nums[j] == vec[2]))
j --;
}
}
while ((k + 1 < nums.size()) && (nums[k] == nums[k+1]))
k ++;
}
return res;
}