15.三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
思路详解:
1. 首先使用sort对数组进行排序
2. 遍历排序后的数组,固定好一个元素nums[i],将left指针初始化为i+1,将right指针初始化为数组末尾。
3. 当left < right时,
- 计算三个元素的和sum = nums[i] + nums[left] + nums[right]。
- 如果sum等于零,将这个三元组[nums[i], nums[left], nums[right]]添加到结果集中。
- 如果sum小于零,说明需要增大和,将left指针右移一位。
- 如果sum大于零,说明需要减小和,将right指针左移一位。
- 注意,如果出现重复的元素,需要跳过,以避免重复的三元组。
4. 继续遍历数组,直到遍历完所有的元素。
代码详解:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end()); // 对数组进行排序,以便后续操作
vector<vector<int>> answer; // 存储结果
for (int i = 0; i < n - 2; i++) { //遍历数组,固定第一个元素
// 避免重复的固定元素
if (i > 0 && nums[i] == nums[i - 1])
continue;
int left = i + 1; // 左指针指向固定元素的下一位
int right = n - 1; // 右指针指向数组末尾
while (left < right) {//保证两个指针不相遇,相遇说明所有情况以及遍历
int sum = nums[i] + nums[left] + nums[right]; // 计算三个元素的和
if (sum < 0) { // 如果和小于零,说明需要增大和,左指针右移一位
left++;
}
else if (sum > 0) { // 如果和大于零,说明需要减小和,右指针左移一位
right--;
}
else { // 和等于零,找到满足条件的三元组
answer.push_back({nums[i], nums[left], nums[right]}); // 将三元组添加到结果中
//如果左指针的下一个元素和本身相同说明我们以及考虑过这个数字,则跳过
while (left < right && nums[left] == nums[left + 1])
left++;
//右指针同理
while (left < right && nums[right] == nums[right - 1])
right--;
//当我们判断完一个三元组后让指针移动指向新的元素,这样可以避免产生相同的三元组
left++;
right--;
}
}
}
return answer;
}
};
面经
- 什么是c++中的模板特化和偏特化,如何实现他们
- 模板特化是指为特定的数据类型提供一个专门的模板定义。当我们希望对于某些特定的类型,模板有不同的实现时,可以使用模板特化。
template <>
void swap<int>(int& a, int& b) {
// 更高效的位操作交换
if (a != b) {
a ^= b;
b ^= a;
a ^= b;
}
}//这里的template <>表示这是一个特化,而void swap<int>(int& a, int& b)表示这是针对int类型的特化实现。
- 偏特化是指对模板参数进行更具体的限制,而不是完全指定一个特定的类型。偏特化可以应用于类模板和函数模板,但通常更多地用于类模板。
template <typename T, typename Allocator>
class Storage {
// ...
};
template <typename T>
class Storage<T, allocator<T>> {
// 针对allocator<T>的优化实现
// ...
};
//在这个例子中,我们没有为T提供一个特定的类型,而是为Allocator参数提供了一个特定的类型allocator<T>,这就是偏特化的一个例子。