本题最难的是对于各种情况的判断,还有遍历和判断后的处理是否越界,基本思路很好理解。
引用一下题解中大佬的思路,很清晰易懂(@吴彦祖)
- 特判,对于数组长度 n,如果数组为 null 或者数组长度小于 3,返回 [ ]。
- 对数组进行排序。
- 遍历排序后数组:
- 若 nums[ i ] > 0:因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回结果。
- 对于重复元素:跳过,避免出现重复解
- 令左指针 L = i + 1,右指针 R = n − 1,当 L < R 时,执行循环:
- 当 nums[ i ] + nums[ L] + nums[ R] == 0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L, R 移到下一位置,寻找新的解
- 若和大于 0,说明 nums[ R] 太大,R 左移
- 若和小于 0,说明 nums[ L] 太小,L 右移
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
int n = nums.size();
//如果数组大小小于三,或最小值大于零,或最大值小于零,都不可能达到三个数的和为零,直接返回
sort(nums.begin(), nums.end());//排序
if(n < 3 || nums.front() > 0 || nums.back() < 0) return ans;
for(int i = 0; i < n-2; i++){//-2去除左右指针
//左右指针始终大于nums[i],如果nums[i]大于零说明已经没有三数之和相加为零的情况了
if(nums[i] > 0) break;
//判断重复的解
if(i > 0 && nums[i] == nums[i-1]) continue;
//判断:三个最小的值相加大于零,说明不可能出现三数之和等于零的情况了,提前终止
if(nums[i] + nums[i+1] + nums[i+2] > 0) break;
//判断:nums[i]和最大的两个值相加小于零,说明当前的nums[i]的值太小了,需要继续向前遍历;
if(nums[i] + nums[n-1] + nums[n-2] < 0) continue;
//双指针:L为最靠近nums[i]的数,R为最大值。循环条件L<R
int L = i+1, R = n-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];//开始计数
if(sum == 0){
//等于零符合条件,压入返回答案的数组中;
ans.push_back({nums[i], nums[L], nums[R]});
//移动左右指针,判断并排除重复的解;
while(L < R && nums[L] == nums[L+1]) L++;
L++;//需要移动到L+1的位置
while(L < R && nums[R] == nums[R-1]) R--;
R--;//同上
}
else if(sum < 0) L++;//和小于零移动左指针
else R--;//和大于零移动右指针
}
}
return ans;
}
};
(本来想练练排序的结果一个sort()就完事了hh)