目录
一、问题描述
这里直接采用的是leetcode上面的问题描述。
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
下面给出示例:
二、解题思想
我们对于这种题很容易想到得是,暴力破解得方法,即使用三个for循环依次判断,很明显这不是出题者得意思,而且三重for循环得时间复杂度为。
所以我们使用排序+双指针得方法,排序是方便去除重复解,双指针依次则与头元素相加判断和是否为0。这样的方法只要使用两重循环,时间复杂度变为了,大大降低了时间复杂度。外层for循环从头到尾扫描元素,与双指针一起判断和是否为0。
双指针分为:头指针和尾指针。
在第一层循环开始时,头指针每次指向首元素得下一元素;尾指针每次指向最后一个元素。
我这里使用得是while循环来判断只要头指针不等于尾指针即不结束
- 判断头元素是否与前一元素相同,相同直接跳过因为重复出现过此三元组。
- 当三元素相加小于0时头指针往后移。判断头指针是否与前指针元素相同,相同则直接跳过进行下次操作。
- 当三元素相加大于0时尾指针往前移。判断尾指针是否与前指针元素相同,相同则直接跳过进行下次操作。
三、解题
1.判断极端情况
- 首先当传入数组nums个数小于3时,不可能存在三元组,此时直接返回空。
- 排序后,如果首元素大于0,那么也不可能存在相加等于0得三元组,可以直接返回空。
- 第一重for循环如果头元素大于0时,那么后面也可以不用判断了同第二种情况,此时可以直接返回找到的三元组。
2.代码实现
vector<vector<int>> threeSum(vector<int>& nums) {
if (nums.size() < 3) {
return {};
}
vector<vector<int>> triplets;
//讲nums从开始到结束排序
sort(nums.begin(), nums.end());
//排序后第一个数大于0不可能存在三个数相加等于0得三元组
if (nums[0] > 0) {
return {};
}
for (int i = 0; i < nums.size()-2; i++) {
//对于排序好得nums 当第i个元素大于0时,后面不可能有相加等于0得三元组
if (nums[i] > 0) {
return triplets;
}
//消除重复,如果这个元素前面出现过了直接进入下一次循环
if (i>0 && nums[i] == nums[i - 1]) {
continue;
}
int j = i + 1;
int k = nums.size()-1;
while (j != k) {
//消除重复元素,头指针前面出现过直接进入下一个循环
if (j>i+1 && nums[j] == nums[j - 1]) {
j++;
continue;
}
//消除重复元素,尾指针后面出现过直接进入下一个循环
if (k < nums.size()-1&& nums[k] == nums[k + 1]) {
k--;
continue;
}
if(nums[i] + nums[j] + nums[k] < 0){
j++;
}
else if(nums[i] + nums[j] + nums[k] > 0 ){
k--;
}
else{
triplets.push_back({ nums[i], nums[j], nums[k] });
j++;
}
}
}
return triplets;
}
总结
在此题种有一些注意得地方,刚开始我使用得是首元素==0来判断后面是否还有相加等于0得三元组,但是有一种极端情况就是0,0,0也是相加等于0得三元组。
对于重复元素得判断要防止头元素和尾指针越界。
以上就是对于本题,我看资料所编写出来得题解,如果有更好的方法,欢迎在下方留言,一起讨论。