Swift|三数之和(3Sum)详细题解 + 注释 + 拓展(LeetCode 15)
✨题目描述
给你一个包含 n
个整数的数组 nums
,判断 nums
中是否存在三个元素 a, b, c
,使得 a + b + c = 0
。请你找出所有和为 0 且不重复的三元组。
注意:答案中不能包含重复的三元组。
🧠解题思路
本题是 LeetCode 中非常经典的“双指针”+“去重”问题,属于中等难度。
✅ 步骤如下:
- 对数组进行排序:便于后续去重处理和双指针的使用。
- 固定一个数 nums[i]:枚举
i
,并为其设置两个指针left
(i+1)和right
(nums.count - 1)。 - 使用双指针向中间靠拢,判断三数之和是否为 0。
- 去重操作:
- 对
i
进行去重,跳过与前一个数相同的情况。 - 对
left
和right
也要去重,防止重复三元组。
- 对
🧾 Swift 代码实现(含详细注释)
func threeSum(_ nums: [Int]) -> [[Int]] {let nums = nums.sorted() // 排序是关键,便于去重和双指针var result: [[Int]] = []for i in 0..<nums.count - 2 {// 如果当前数字和前一个数字相同,跳过,避免重复三元组if i > 0 && nums[i] == nums[i - 1] {continue}var left = i + 1var right = nums.count - 1while left < right {let sum = nums[i] + nums[left] + nums[right]if sum == 0 {// 找到一个有效三元组result.append([nums[i], nums[left], nums[right]])// 去重:移动 left 指针跳过相同的数while left < right && nums[left] == nums[left + 1] {left += 1}// 去重:移动 right 指针跳过相同的数while left < right && nums[right] == nums[right - 1] {right -= 1}left += 1right -= 1} else if sum < 0 {// 总和偏小,左指针右移以增大总和left += 1} else {// 总和偏大,右指针左移以减小总和right -= 1}}}return result
}
⏱️时间复杂度分析
步骤 | 复杂度 |
---|---|
排序 | O(nlogn) |
遍历 + 双指针查找 | O(n^2) |
总体时间复杂度 | O(n²) |
n
是数组的长度。- 最坏情况下,每个元素都要与后面的所有元素进行组合查找。
🧠空间复杂度
- 使用了常数级别的辅助空间(除了结果数组):O(1)。
- 如果考虑返回结果的空间,那么是 O(k),其中
k
为结果中三元组的个数。
🔍输入输出示例
let nums = [-1, 0, 1, 2, -1, -4]
print(threeSum(nums))
// 输出: [[-1, -1, 2], [-1, 0, 1]]
🧱边界情况说明
输入 | 输出 | 说明 |
---|---|---|
[] | [] | 空数组 |
[0, 0, 0] | [[0,0,0]] | 需要处理重复值 |
[1, 2, -2, -1] | [] | 没有满足条件的组合 |
🧩拓展与优化
-
如果要求和为 target 而非 0:
- 将判断条件
sum == 0
改为sum == target
即可。 - 本题可以推广为
kSum
问题(如 Two Sum、Four Sum)。
- 将判断条件
-
去重逻辑处理建议封装为函数:
- 提高代码可读性与复用性。
-
Swift 中使用 Set 存储结果避免重复:
- 如果输入较多或存在重复项较多,可以考虑用
Set<[Int]>
先去重再转成[[Int]]
。
- 如果输入较多或存在重复项较多,可以考虑用
🏁总结
- 本题考察的是数组排序 + 双指针技巧。
- 核心是合理处理重复元素,避免重复解。
- 时间复杂度为 O(n²),在面试中属于经典问题,建议掌握。
如果你觉得有用,欢迎点赞、评论支持我继续更新 💪
你也可以在评论区分享你遇到的变体,我来帮你一起解答!