目录
前言
在上一篇文章里提到了通过先排后写的思路,本文就利用这个思路完成力扣hot100里的15. 三数之和,帮助更好的加深对排序的认识。
思路分析
“三数之和” 问题的核心是在数组中找到所有和为 0 的三元组,且不包含重复解。采用排序 + 双指针的策略,具体逻辑如下:
排序:先对数组排序,为后续去重和双指针遍历奠定基础。固定一个数,双指针找另外两个数:固定第一个数nums[i],将问题转化为 “在i之后的子数组中找两个数,使它们的和为-nums[i]”,用左指针j(从i+1开始)和右指针k(从数组末尾开始)遍历查找。
去重:通过判断相邻元素是否相等,跳过重复的nums[i]和nums[j],避免生成重复的三元组。
时间复杂度与空间复杂度
时间复杂度:O(),排序操作的时间复杂度为O(
);外层循环遍历n个元素,内层循环中双指针遍历的时间复杂度为O(n),因此整体时间复杂度由O(
)主导。
空间复杂度:O()(排序操作的递归栈或迭代空间开销),若不考虑结果存储的空间,额外空间复杂度为O(
);若考虑结果存储,空间复杂度取决于有效三元组的数量,最坏情况下为O(
)。
代码示例
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
// 存储最终所有和为0的三元组
vector<vector<int>> ans;
// 对数组排序,为去重和双指针遍历做准备
sort(nums.begin(), nums.end());
// 数组长度
int n = nums.size();
// 固定第一个数nums[i]
for (int i = 0; i < n; ++i) {
// 去重:若当前数和前一个数相等,跳过(避免重复三元组)
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 目标值:另外两个数的和需等于 -nums[i]
int target = -nums[i];
// 右指针k初始化为数组末尾
int k = n - 1;
// 左指针j从i+1开始遍历
for (int j = i + 1; j < n; ++j) {
// 去重:若当前j对应的数和前一个数相等,跳过(避免重复三元组)
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
// 双指针收缩:当j < k且两数之和大于target时,右指针左移
while (j < k && nums[j] + nums[k] > target) {
k--;
}
// 若j和k相遇,说明后续无符合条件的组合,退出循环
if (j == k) {
break;
}
// 若两数之和等于target,找到一个有效三元组
if (nums[j] + nums[k] == target) {
ans.push_back({nums[i], nums[j], nums[k]});
}
}
}
return ans;
}
};
总结
三数之和的思路大概是“排序”+“双指针”,希望通过这题的介绍,能够加强一些码友对排序和双指针的理解。
460

被折叠的 条评论
为什么被折叠?



