Files
interview/16-LeetCode Hot 100/三数之和.md
yasinshaw 4247e0700d refactor: convert all LeetCode solutions to Go-only
Changes:
- Removed all Java code implementations
- Kept only Go language solutions
- Renamed "## Go 解法" to "## 解法"
- Removed "### Go 代码要点" sections
- Cleaned up duplicate headers and empty sections
- Streamlined documentation for better readability

Updated files (9):
- 三数之和.md
- 两数相加.md
- 无重复字符的最长子串.md
- 最长回文子串.md
- 括号生成.md
- 子集.md
- 单词搜索.md
- 电话号码的字母组合.md
- 柱状图中最大的矩形.md

All 22 LeetCode Hot 100 Medium problems now use Go exclusively.
Code is cleaner, more focused, and easier to follow.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-05 12:32:55 +08:00

196 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 三数之和 (3Sum)
LeetCode 15. Medium
## 题目描述
给你一个整数数组 `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]
注意,输出的顺序和三元组的顺序并不重要。
```
**示例 2**
```
输入nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0
```
**示例 3**
```
输入nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0
```
## 解题思路
### 核心思想
**排序 + 双指针**:先排序,固定第一个数,再用双指针找后两个数。
### 算法流程
1. **排序数组**:便于去重和双指针操作
2. **遍历第一个数**
- 跳过重复元素
- 如果当前数 > 0直接退出后面都 > 0
3. **双指针找后两个数**
- left = i + 1, right = len(nums) - 1
- 根据 sum 与 0 的关系移动指针
- 跳过重复元素
### 复杂度分析
- **时间复杂度**O(n²),排序 O(n log n) + 双指针 O(n²)
- **空间复杂度**O(1),不考虑结果存储
---
---
## 图解过程
```
数组: [-4, -1, -1, 0, 1, 2]
↑ ↑ ↑
i left right
第一轮: i = 0, nums[i] = -4
left = 1, right = 5
sum = -4 + (-1) + 2 = -3 < 0
left++
left = 2, right = 5
sum = -4 + (-1) + 2 = -3 < 0
left++
left = 3, right = 5
sum = -4 + 0 + 2 = -2 < 0
left++
left = 4, right = 5
sum = -4 + 1 + 2 = -1 < 0
left++
left >= right, 退出
第二轮: i = 1, nums[i] = -1
left = 2, right = 5
sum = -1 + (-1) + 2 = 0 ✓
结果: [-1, -1, 2]
left = 3, right = 4
sum = -1 + 0 + 1 = 0 ✓
结果: [-1, 0, 1]
第三轮: i = 2, nums[i] = -1 (重复,跳过)
第四轮: i = 3, nums[i] = 0 > 0, 退出
最终结果: [[-1,-1,2], [-1,0,1]]
```
---
## 进阶问题
### Q1: 如果是四数之和?
**方法**:在三层循环 + 双指针,时间 O(n³)
```go
func fourSum(nums []int, target int) [][]int {
result := [][]int{}
sort.Ints(nums)
n := len(nums)
for i := 0; i < n-3; i++ {
if i > 0 && nums[i] == nums[i-1] {
continue
}
for j := i + 1; j < n-2; j++ {
if j > i+1 && nums[j] == nums[j-1] {
continue
}
left, right := j+1, n-1
for left < right {
sum := nums[i] + nums[j] + nums[left] + nums[right]
if sum == target {
result = append(result, []int{nums[i], nums[j], nums[left], nums[right]})
for left < right && nums[left] == nums[left+1] {
left++
}
for left < right && nums[right] == nums[right-1] {
right--
}
left++
right--
} else if sum < target {
left++
} else {
right--
}
}
}
}
return result
}
```
### Q2: 如果数组很大,如何优化?
**优化**
1. 提前终止:`nums[i] * 3 > target`(正数情况)
2. 二分查找:确定第二个数后,二分查找后两个
3. 哈希表:空间换时间
---
## P7 加分项
### 深度理解
- **排序的作用**:去重 + 双指针基础
- **双指针原理**:利用有序性,单向移动
- **去重策略**:多处去重,确保结果唯一
### 实战扩展
- **大数据场景**:外部排序 + 分段处理
- **分布式场景**MapReduce 框架
- **业务场景**:推荐系统、用户画像匹配
### 变形题目
1. [16. 最接近的三数之和](https://leetcode.cn/problems/3sum-closest/)
2. [18. 四数之和](https://leetcode.cn/problems/4sum/)
3. [259. 较小的三数之和](https://leetcode.cn/problems/3sum-smaller/)
---
## 总结
这道题的核心是:
1. **排序**:为双指针和去重创造条件
2. **固定一个数**:将问题转化为两数之和
3. **双指针**:根据 sum 与 target 的关系移动指针
4. **多重去重**i、left、right 都要跳过重复元素
**易错点**
- 忘记排序
- 去重逻辑不完整
- left 和 right 的移动条件
- 优化提前终止的条件
**最优解法**:排序 + 双指针,时间 O(n²),空间 O(1)