题目链接
题目大意
题目已经说得很明白了,这里不再赘述。
解题思路
思路一(TLE)
先用两个 map 映射每个数的值与其下标,然后用两次循环去查找需要的数是否在映射表中,这里用下标来防止数字重复,将三个数排序后插入集合用来消除重复解,可惜超时,第312个样例 [0, 0, ....., 0] 过不去。参考代码如下
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set <vector <int>> ans;
unordered_map <int, int> hash;
unordered_map <int, int> index;
for(int i = 0; i < nums.size(); i++) {
hash[nums[i]] = nums[i];
index[nums[i]] = i;
}
for(int i = 0; i < nums.size(); i++) {
for(int j = i + 1; j < nums.size(); j++) {
int k = -nums[i] - nums[j];
if(hash.find(k) != hash.end() && index[k] != i && index[k] != j) {
int a = nums[i], b = nums[j], c = hash[k];
if(a > b) swap(a, b);
if(a > c) swap(a, c);
if(b > c) swap(b, c);
vector <int> temp {a, b, c};
ans.insert(temp);
}
}
}
return vector<vector <int>> (ans.begin(), ans.end());
}
};
思路二(TLE)
参考题解后,用比较 naive 的办法进行双指针法尝试。首先排序,然后针对每一个数,在它紧左边取一个指针向左走,在它紧右边取一个指针向右走,直到某个指针到了边界为止。同样使用了集合来消除重复解,可惜仍然超时,参考代码如下。这里怀疑超时的主要原因在于用集合消除重复解的过程。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set <vector <int>> ans;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i++) {
for(int j = i - 1, k = i + 1; j > -1 && k < nums.size();) {
int sum = nums[j] + nums[i] + nums[k];
if(sum == 0){
ans.insert(vector <int> {nums[j], nums[i], nums[k]});
j--;
k++;
}
else if(sum > 0) j--;
else k++;
}
}
return vector<vector <int>> (ans.begin(), ans.end());
}
};
思路三
阅读大佬的题解后,发现可以直接在双指针判断过程中消除重复解。对数组排序后,固定每一个 nums[i], 用 L 指向 i 紧右边的数,R 指向数组最后一个数。如果 nums[i] > 0, 则三数之和必然大于 0 ,结束循环。 如果 nums[i] == nums[i - 1] , 说明该数字重复,会导致结果重复,应该跳过;当 sum == 0 时, nums[L] == nums[L + 1] 会导致结果重复,应该跳过;同样,当 sum == 0 时,nums[R] == nums[R - 1] 时会导致结果重复,应该跳过。参考代码如下:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector <vector <int>> ans;
sort(nums.begin(), nums.end());
int len = nums.size();
for(int i = 0; i < len; i++) {
if(nums[i] > 0) break;
if(i > 0 && nums[i] == nums[i - 1]) continue;
for(int L = i + 1, R = len - 1; L < R;) {
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.push_back(vector <int> {nums[i], nums[L], nums[R]});
while(L < R && nums[L] == nums[L + 1]) L++;
while(L < R && nums[R] == nums[R - 1]) R--;
L++;
R--;
}
else if(sum < 0) L++;
else R--;
}
}
return ans;
}
};
解题感悟
双指针的用法很活啊,需要多多理解灵活运用。
set 用来去重真的很费时间,或许可以直接 vector 存储然后手动去重。