From 24d5923f5e45757d88e361b6cfc2441bc886dd2f Mon Sep 17 00:00:00 2001 From: yasinshaw Date: Sun, 8 Mar 2026 20:59:34 +0800 Subject: [PATCH] vault backup: 2026-03-08 20:59:34 --- .obsidian/workspace.json | 4 +- 16-LeetCode Hot 100/三数之和-改进版示例.md | 730 +++++++++++++++++++++ 算法解题思路改进方案.md | 386 +++++++++++ 3 files changed, 1118 insertions(+), 2 deletions(-) create mode 100644 16-LeetCode Hot 100/三数之和-改进版示例.md create mode 100644 算法解题思路改进方案.md diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index a968f69..278495d 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -198,6 +198,8 @@ }, "active": "fcbc762a80282002", "lastOpenFiles": [ + "16-LeetCode Hot 100/三数之和-改进版示例.md", + "算法解题思路改进方案.md", "16-LeetCode Hot 100/单词搜索.md", "16-LeetCode Hot 100/从前序与中序遍历序列构造二叉树.md", "16-LeetCode Hot 100/除自身以外数组的乘积.md", @@ -227,8 +229,6 @@ "16-LeetCode Hot 100/二叉树的中序遍历.md", "16-LeetCode Hot 100/最小栈.md", "16-LeetCode Hot 100/最长连续序列.md", - "16-LeetCode Hot 100/完全平方数.md", - "16-LeetCode Hot 100/最大正方形.md", "16-LeetCode Hot 100", "00-项目概述", "questions/15-简历面试", diff --git a/16-LeetCode Hot 100/三数之和-改进版示例.md b/16-LeetCode Hot 100/三数之和-改进版示例.md new file mode 100644 index 0000000..5c8f815 --- /dev/null +++ b/16-LeetCode Hot 100/三数之和-改进版示例.md @@ -0,0 +1,730 @@ +# 三数之和 (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]] +``` + +**示例 2**: +``` +输入:nums = [0,1,1] +输出:[] +``` + +## 思路推导 + +### 暴力解法分析 + +```python +def threeSum_brute(nums): + result = [] + n = len(nums) + for i in range(n): + for j in range(i+1, n): + for k in range(j+1, n): + if nums[i] + nums[j] + nums[k] == 0: + # 使用集合去重 + triplet = sorted([nums[i], nums[j], nums[k]]) + if triplet not in result: + result.append(triplet) + return result +``` + +**时间复杂度**: O(n³) +**空间复杂度**: O(1) (不考虑结果存储) +**问题**: n=2000时,操作次数约80亿次,超时! + +### 优化思考 - 降维思想 + +**观察**: 固定第一个数后,问题变成"两数之和" +``` +三数之和: nums[i] + nums[j] + nums[k] = 0 +↓ 固定 nums[i] +两数之和: nums[j] + nums[k] = -nums[i] +``` + +**两数之和的优化**: +- 暴力: O(n²) 遍历所有对 +- 优化: O(n) 双指针(前提:数组有序) + +**总复杂度**: O(n) × O(n) = O(n²) ✅ + +### 为什么排序后能用双指针? + +**核心原理:单调性** + +``` +有序数组: [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + +如果 sum = nums[left] + nums[right] < 0: + - 需要增大和 + - left++ → nums[left]增大(数组升序) → sum增大 + - right-- → nums[right]减小 → sum减小 ✗ + +如果 sum = nums[left] + nums[right] > 0: + - 需要减小和 + - right-- → nums[right]减小 → sum减小 + - left++ → nums[left]增大 → sum增大 ✗ +``` + +**为什么无序数组不行?** +``` +无序: [2, -1, 0, -4, 1] + ↑ ↑ ↑ + i L R + +sum = 2 + (-1) + 1 = 2 > 0 +应该移动哪个指针? 无法确定! +``` + +### 排序的三大作用 + +1. **去重基础**:相同数字相邻,便于跳过 +2. **双指针前提**:利用单调性优化 +3. **提前终止**:排序后,如果当前数>0,后面都>0 + +## 解题思路 + +### 核心思想 + +**排序 + 双指针 + 去重** +- 排序:为双指针和去重创造条件 +- 固定一个数:将三数问题降维为两数问题 +- 双指针: O(n) 解决两数之和 +- 多重去重:避免重复结果 + +### 算法流程(详细版) + +#### 步骤1:预处理 - 排序 + +```python +nums.sort() # [-1,0,1,2,-1,-4] → [-4,-1,-1,0,1,2] +``` + +**为什么排序?** +``` +原始: [-1,0,1,2,-1,-4] → 重复:-1出现两次 +排序: [-4,-1,-1,0,1,2] → 重复:-1相邻,便于跳过 +``` + +#### 步骤2:外层循环 - 固定第一个数 + +```python +for i in range(len(nums) - 2): # ← 为什么-2?留2个数给双指针 + + # 去重1:跳过重复的第一个数 + if i > 0 and nums[i] == nums[i-1]: + continue + + # 提前终止:如果最小数>0,后面不可能和为0 + if nums[i] > 0: + break + + # 双指针找后两个数 + left, right = i + 1, len(nums) - 1 + ... +``` + +**关键点解析**: + +**Q1: 为什么循环到 `len(nums)-2`?** +``` +数组: [0, 1, 2] +索引: 0 1 2 + +如果 i = 2 (最后一个元素): + left = 3 → 越界! + +所以 i 最大 = len(nums) - 3 = 1 +循环条件: range(len(nums) - 2) → [0, 1] +``` + +**Q2: 为什么判断 `i > 0`?** +``` +i = 0:第一个元素,没有前一个元素,不用判断重复 +i > 0:后续元素,需要判断是否与前一个相同 + +错误写法: +if nums[i] == nums[i-1]: # i=0时越界! + +正确写法: +if i > 0 and nums[i] == nums[i-1]: # 安全 +``` + +**Q3: 为什么break而不是continue?** +``` +排序后: [-4, -1, -1, 0, 1, 2] + ↑ + i=3, nums[i]=0 > 0 + +后续: [1, 2] 都 > 0 +三数和: 0 + 1 + 2 = 3 > 0 + +结论:后面不可能有和为0的组合,直接退出 +``` + +#### 步骤3:内层双指针 - 两数之和 + +```python +while left < right: + current_sum = nums[i] + nums[left] + nums[right] + + if current_sum == 0: + result.append([nums[i], nums[left], nums[right]]) + + # 去重2:跳过重复的left + while left < right and nums[left] == nums[left+1]: + left += 1 + + # 去重3:跳过重复的right + while left < right and nums[right] == nums[right-1]: + right -= 1 + + # 继续寻找下一组 + left += 1 + right -= 1 + + elif current_sum < 0: + left += 1 # 需要更大的和 + else: + right -= 1 # 需要更小的和 +``` + +**为什么找到答案后要同时移动两个指针?** + +``` +数组: [-2, 0, 1, 1, 2] + i L R + +找到: -2 + 0 + 2 = 0 ✓ + +如果只移动L: L=2, nums[L]=1 + sum = -2 + 1 + 2 = 1 > 0 → R-- + 但这样会错过可能的组合 + +正确:同时移动 + L=1, R=3: -2 + 1 + 1 = 0 ✓ (找到第二个) +``` + +### 关键细节说明 + +#### 细节1:去重逻辑的三重保障 + +```python +# 去重1:外层循环,跳过重复的第一个数 +if i > 0 and nums[i] == nums[i-1]: + continue + +# 去重2:找到答案后,跳过重复的left +while left < right and nums[left] == nums[left+1]: + left += 1 + +# 去重3:找到答案后,跳过重复的right +while left < right and nums[right] == nums[right-1]: + right -= 1 +``` + +**示例**: +``` +输入: [-2, -1, -1, 0, 1, 1, 2] + +第一轮: i=0, nums[i]=-2 + 双指针找到: [-2, 0, 2], [-2, 1, 1] + +第二轮: i=1, nums[i]=-1 + 双指针找到: [-1, -1, 2], [-1, 0, 1] + +第三轮: i=2, nums[i]=-1 + 与i=1相同 → 跳过 (去重1) + +第四轮: i=3, nums[i]=0 + 双指针找到: [0, -1, 1] → 已存在 + +第五轮: i=4, nums[i]=1 + 与i=3相同 → 跳过 (去重1) + +结果: [[-2,0,2], [-2,1,1], [-1,-1,2], [-1,0,1]] +``` + +#### 细节2:为什么 `left < right` 而不是 `<=`? + +```python +while left < right: # 正确 + ... + +while left <= right: # 错误 + ... +``` + +**原因**: +``` +left = right 时,只有一个元素 +两数之和需要两个不同的元素 +所以 left < right,不允许相同位置 +``` + +#### 细节3:为什么先去重再移动? + +```python +# 正确顺序 +while left < right and nums[left] == nums[left+1]: + left += 1 # 先跳过所有重复 +left += 1 # 再移动到新元素 + +# 错误顺序 +left += 1 # 先移动 +while left < right and nums[left] == nums[left-1]: + left += 1 # 可能漏掉某些重复 +``` + +### 边界条件分析 + +#### 边界1:数组长度不足 + +``` +输入: [0, 1] +输出: [] + +分析: len(nums) = 2 +循环: range(2-2) = range(0) → 不执行 +``` + +#### 边界2:全部为0 + +``` +输入: [0, 0, 0, 0] +输出: [[0, 0, 0]] + +排序: [0, 0, 0, 0] + +i=0: + left=1, right=3 + sum = 0+0+0 = 0 ✓ → result = [[0,0,0]] + 去重left: left=1,2,3 (跳过所有0) + 去重right: right=3,2,1 + left >= right,退出内层循环 + +i=1: + nums[1] == nums[0] → 跳过 + +最终: [[0, 0, 0]] +``` + +#### 边界3:没有答案 + +``` +输入: [0, 1, 2] +输出: [] + +排序: [0, 1, 2] + +i=0: + left=1, right=2 + sum = 0+1+2 = 3 > 0 → right-- + + left=1, right=1 → left >= right,退出 + +i=1: + nums[1] = 1 > 0 → break + +最终: [] +``` + +### 复杂度分析(详细版) + +#### 时间复杂度 + +``` +1. 排序: O(n log n) + - 快速排序平均情况 + +2. 外层循环: O(n) + for i in range(n) + +3. 内层双指针: O(n) + while left < right + - 每次循环 left++ 或 right-- + - 最多执行 n 次 + +4. 总复杂度: O(n log n) + O(n²) = O(n²) + - n² >> n log n (当 n 较大时) + - 渐近复杂度取最高阶 +``` + +#### 空间复杂度 + +``` +1. 排序栈空间: O(log n) + - 快速排序递归深度 + +2. 结果存储: O(k) + - k 为结果数量 + +3. 指针变量: O(1) + +4. 总复杂度: O(log n) (不考虑结果存储) +``` + +## 代码实现 + +```python +def threeSum(nums): + """ + 三数之和 - 排序 + 双指针解法 + + Args: + nums: 输入数组 + + Returns: + 所有不重复的三元组,和为0 + """ + result = [] + nums.sort() # 步骤1:排序 + + # 步骤2:外层循环,固定第一个数 + for i in range(len(nums) - 2): + + # 去重1:跳过重复的第一个数 + if i > 0 and nums[i] == nums[i-1]: + continue + + # 提前终止:如果最小数>0,后面不可能和为0 + if nums[i] > 0: + break + + # 步骤3:双指针找后两个数 + left, right = i + 1, len(nums) - 1 + + while left < right: + current_sum = nums[i] + nums[left] + nums[right] + + if current_sum == 0: + # 找到答案 + result.append([nums[i], nums[left], nums[right]]) + + # 去重2:跳过重复的left + while left < right and nums[left] == nums[left+1]: + left += 1 + + # 去重3:跳过重复的right + while left < right and nums[right] == nums[right-1]: + right -= 1 + + # 继续寻找下一组 + left += 1 + right -= 1 + + elif current_sum < 0: + # 和太小,需要增大 → left++ + left += 1 + else: + # 和太大,需要减小 → right-- + right -= 1 + + return result +``` + +## 执行过程演示 + +### 输入: nums = [-1, 0, 1, 2, -1, -4] + +``` +初始状态: +nums = [-1, 0, 1, 2, -1, -4] +排序后: [-4, -1, -1, 0, 1, 2] +result = [] + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +第一轮: i = 0, nums[i] = -4 + [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + + sum = -4 + (-1) + 2 = -3 < 0 + left++ → left = 1 + + [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + + sum = -4 + (-1) + 2 = -3 < 0 + left++ → left = 2 + + [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + + sum = -4 + (-1) + 2 = -3 < 0 + left++ → left = 3 + + [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + + sum = -4 + 0 + 2 = -2 < 0 + left++ → left = 4 + + [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + + sum = -4 + 1 + 2 = -1 < 0 + left++ → left = 5 + + left >= right,退出内层循环 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +第二轮: i = 1, nums[i] = -1 + [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + + sum = -1 + (-1) + 2 = 0 ✓ + result = [[-1, -1, 2]] + + 去重left: nums[2] = -1 == nums[3] = 0? No + 去重right: nums[5] = 2 == nums[4] = 1? No + left++, right-- → left = 3, right = 4 + + [-4, -1, -1, 0, 1, 2] + ↑ ↑ ↑ + i left right + + sum = -1 + 0 + 1 = 0 ✓ + result = [[-1, -1, 2], [-1, 0, 1]] + + 去重left: nums[3] = 0 == nums[4] = 1? No + 去重right: nums[4] = 1 == nums[3] = 0? No + left++, right-- → left = 4, right = 3 + + left >= right,退出内层循环 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +第三轮: i = 2, nums[i] = -1 + [-4, -1, -1, 0, 1, 2] + ↑ + i + + 判断: nums[2] == nums[1] == -1? Yes + 跳过 (去重1) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +第四轮: i = 3, nums[i] = 0 + [-4, -1, -1, 0, 1, 2] + ↑ + i + + 判断: nums[3] > 0? Yes + break (提前终止) + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +最终结果: [[-1, -1, 2], [-1, 0, 1]] +``` + +## 常见错误 + +### 错误1:忘记排序 + +❌ 错误写法: +```python +def threeSum(nums): + result = [] + for i in range(len(nums)): + left, right = i + 1, len(nums) - 1 + while left < right: + if nums[i] + nums[left] + nums[right] == 0: + result.append([nums[i], nums[left], nums[right]]) + # ... 双指针移动 + return result +``` + +**问题**:无序数组无法使用双指针 + +✅ 正确写法: +```python +nums.sort() # 先排序! +for i in range(len(nums) - 2): + ... +``` + +### 错误2:去重逻辑不完整 + +❌ 错误写法: +```python +if nums[i] == nums[i-1]: # i=0时越界 + continue +``` + +✅ 正确写法: +```python +if i > 0 and nums[i] == nums[i-1]: + continue +``` + +### 错误3:指针移动条件错误 + +❌ 错误写法: +```python +if current_sum == 0: + result.append([nums[i], nums[left], nums[right]]) + left += 1 # 只移动一个指针 +``` + +✅ 正确写法: +```python +if current_sum == 0: + result.append([nums[i], nums[left], nums[right]]) + # 去重 + while left < right and nums[left] == nums[left+1]: + left += 1 + while left < right and nums[right] == nums[right-1]: + right -= 1 + # 同时移动 + left += 1 + right -= 1 +``` + +### 错误4:循环边界错误 + +❌ 错误写法: +```python +for i in range(len(nums)): # 可能越界 + left, right = i + 1, len(nums) - 1 +``` + +✅ 正确写法: +```python +for i in range(len(nums) - 2): # 留2个位置 + left, right = i + 1, len(nums) - 1 +``` + +## 变体问题 + +### 变体1:四数之和 (LeetCode 18) + +**题目**:找出四数之和等于target的所有组合 + +**思路**:三层循环 + 双指针 +```python +def fourSum(nums, target): + result = [] + nums.sort() + + for i in range(len(nums) - 3): + for j in range(i + 1, len(nums) - 2): + left, right = j + 1, len(nums) - 1 + + while left < right: + sum = nums[i] + nums[j] + nums[left] + nums[right] + + if sum == target: + result.append([nums[i], nums[j], nums[left], nums[right]]) + # 去重... + elif sum < target: + left += 1 + else: + right -= 1 + + return result +``` + +**时间复杂度**: O(n³) + +### 变体2:最接近的三数之和 (LeetCode 16) + +**题目**:找出三数之和最接近target的组合 + +**思路**:双指针 + 记录最小差值 +```python +def threeSumClosest(nums, target): + nums.sort() + closest = float('inf') + + for i in range(len(nums) - 2): + left, right = i + 1, len(nums) - 1 + + while left < right: + current_sum = nums[i] + nums[left] + nums[right] + + if abs(current_sum - target) < abs(closest - target): + closest = current_sum + + if current_sum == target: + return target # 完全匹配 + elif current_sum < target: + left += 1 + else: + right -= 1 + + return closest +``` + +## 总结 + +### 核心要点 + +1. **排序的作用** + - 去重基础(相同元素相邻) + - 双指针前提(利用单调性) + - 提前终止(最小数>target时退出) + +2. **降维思想** + - 三数之和 → 固定一个数 → 两数之和 + - O(n³) → O(n²) + +3. **去重策略** + - 外层循环:跳过重复的第一个数 + - 内层循环:找到答案后跳过重复的left和right + - 多重去重确保结果唯一 + +4. **双指针原理** + - 利用有序数组的单调性 + - 根据sum与target的关系单向移动指针 + - 时间复杂度从O(n²)降到O(n) + +### 易错点 + +- [ ] 忘记排序 +- [ ] 去重逻辑不完整(i>0判断) +- [ ] 循环边界错误(len(nums)-2) +- [ ] 找到答案后只移动一个指针 +- [ ] 提前终止条件用continue而非break + +### 最优解法 + +**排序 + 双指针** +- 时间复杂度: O(n²) +- 空间复杂度: O(log n) (排序栈空间) + +### P7加分项 + +**深度理解**: +- 排序的三大作用(去重、双指针、提前终止) +- 双指针的原理(单调性) +- 降维思想(三维→二维) + +**实战扩展**: +- 大数据场景:外部排序 + 分段处理 +- 分布式场景:MapReduce框架 +- 业务场景:推荐系统、用户画像匹配 + +**变体题目**: +- [16. 最接近的三数之和](https://leetcode.cn/problems/3sum-closest/) +- [18. 四数之和](https://leetcode.cn/problems/4sum/) +- [259. 较小的三数之和](https://leetcode.cn/problems/3sum-smaller/) diff --git a/算法解题思路改进方案.md b/算法解题思路改进方案.md new file mode 100644 index 0000000..e498fbd --- /dev/null +++ b/算法解题思路改进方案.md @@ -0,0 +1,386 @@ +# 算法解题思路改进方案 + +## 当前状态分析 + +经过分析,现有LeetCode题目的解题思路已经包含了: +- ✅ 核心思想 +- ✅ 算法流程 +- ✅ 复杂度分析 +- ✅ 代码实现 +- ✅ 部分题目的图解 + +## 改进方向 + +### 1. 解题思路部分需要增强 + +**改进前** (以三数之和为例): +```markdown +### 核心思想 +**排序 + 双指针**:先排序,固定第一个数,再用双指针找后两个数。 + +### 算法流程 +1. **排序数组**:便于去重和双指针操作 +2. **遍历第一个数**: + - 跳过重复元素 + - 如果当前数 > 0,直接退出 +3. **双指针找后两个数**: + - left = i + 1, right = len(nums) - 1 + - 根据 sum 与 0 的关系移动指针 +``` + +**改进后**: +```markdown +### 核心思想 +**排序 + 双指针**:先排序,固定第一个数,再用双指针找后两个数。 + +**为什么这样思考?** +1. **排序的作用**: + - 去除重复结果(相同数相邻) + - 使数组有序,才能使用双指针 + - 提前终止(如果当前数>0,后面都>0) + +2. **双指针的原理**: + - 数组有序后,如果 sum < target,需要增大 → left++ + - 如果 sum > target,需要减小 → right-- + - 利用单调性,避免暴力枚举 + +3. **降维思想**: + - 三数之和 → 固定一个数 → 两数之和 + - O(n³) → O(n²) + +### 解题思路推导过程 + +**第一步:暴力解法分析** +``` +暴力解法:三层循环枚举所有可能 +for i in range(n): + for j in range(i+1, n): + for k in range(j+1, n): + if nums[i] + nums[j] + nums[k] == 0: + result.add([nums[i], nums[j], nums[k]]) + +时间复杂度: O(n³) +空间复杂度: O(1) +问题:效率太低,无法通过 +``` + +**第二步:优化思考 - 能否降维?** +- 观察到固定第一个数后,问题变成"两数之和" +- 两数之和可以用双指针 O(n) 解决 +- 总复杂度: O(n) × O(n) = O(n²) + +**第三步:双指针的前提条件** +- 为什么排序后才能用双指针? + - 如果 nums[left] + nums[right] < 0 + - 由于数组升序,增大left → 和会变大 + - 减小right → 和会变小 + - 这就是"单调性"的作用 + +### 详细算法流程 + +**步骤1:预处理 - 排序** +```python +nums.sort() # O(n log n) +``` +- 作用:去重、双指针基础、提前终止 + +**步骤2:外层循环 - 固定第一个数** +```python +for i in range(len(nums) - 2): + # 去重:跳过重复元素 + if i > 0 and nums[i] == nums[i-1]: + continue + + # 提前终止:如果最小数>0,后面不可能=0 + if nums[i] > 0: + break + + # 双指针找后两个数 + twoSum(nums, i+1, -nums[i]) +``` + +**关键点**: +- 为什么循环到 `len(nums)-2`? 需要留2个数给双指针 +- 为什么判断 `i > 0`? 第一个元素不用判断重复 + +**步骤3:内层双指针 - 两数之和** +```python +def twoSum(nums, start, target): + left, right = start, len(nums) - 1 + + while left < right: + current_sum = nums[left] + nums[right] + + if current_sum == target: + result.append([-target, nums[left], nums[right]]) + + # 去重:跳过重复的left + while left < right and nums[left] == nums[left+1]: + left += 1 + # 去重:跳过重复的right + while left < right and nums[right] == nums[right-1]: + right -= 1 + + # 同时移动,寻找下一组解 + left += 1 + right -= 1 + + elif current_sum < target: + left += 1 # 需要更大的和 + else: + right -= 1 # 需要更小的和 +``` + +**关键点**: +- 为什么找到答案后还要跳过重复? 避免重复结果 +- 为什么找到答案后要同时移动? 继续寻找其他组合 + +### 关键细节说明 + +**细节1:为什么是 `if i > 0`?** +```python +# 错误写法 +if nums[i] == nums[i-1]: # i=0时会越界! + +# 正确写法 +if i > 0 and nums[i] == nums[i-1]: # 第一个元素不用判断 +``` + +**细节2:为什么找到答案后要同时移动?** +``` +假设: [-2, 0, 1, 1, 2] + i L R + +找到: -2 + 0 + 2 = 0 ✓ + +如果只移动一个指针: +- L++: [-2, 0, 1, 1, 2] → -2 + 1 + 2 = 1 > 0 → R-- + 但这样可能错过其他组合 + +正确做法:同时移动 +- L++ and R--: 继续寻找其他可能的组合 +``` + +**细节3:为什么break而不是continue?** +```python +if nums[i] > 0: + break # 正确:后面的数都>0,不可能和为0 + # continue # 错误:会继续无意义的循环 +``` +``` +### 边界条件分析 + +**边界1:数组长度不足** +``` +输入: [0, 1] +输出: [] +原因:长度<3,无法组成三元组 +``` + +**边界2:全部为0** +``` +输入: [0, 0, 0, 0] +输出: [[0, 0, 0]] +去重逻辑:只保留一个组合 +``` + +**边界3:有重复元素** +``` +输入: [-1, -1, 0, 1] +输出: [[-1, 0, 1]] +去重逻辑:跳过第二个-1 +``` + +### 复杂度分析(详细版) + +**时间复杂度**: +``` +- 排序: O(n log n) +- 外层循环: O(n) +- 内层双指针: O(n) +- 总计: O(n log n) + O(n²) = O(n²) + +为什么主项是O(n²)? +- n² >> n log n (当n较大时) +- 渐近复杂度取最高阶 +``` + +**空间复杂度**: +``` +- 排序:O(log n) (快速排序栈空间) +- 结果存储:O(k) (k为结果数量) +- 指针变量:O(1) +- 总计:O(log n) (不考虑结果存储) +``` +``` + +### 2. 增加思考过程部分 + +在"解题思路"之前,增加"思路推导"部分: +- 从暴力解法开始 +- 分析暴力解法的瓶颈 +- 逐步优化思路 +- 最终得到最优解 + +### 3. 增加图解说明 + +为每个关键步骤添加: +- 初始状态图 +- 中间过程图 +- 最终结果图 +- 使用ASCII art或文字描述 + +### 4. 增加常见错误 + +列出易错点: +- 边界条件错误 +- 去重逻辑错误 +- 指针移动条件错误 +- 提前终止条件错误 + +### 5. 增加变体问题 + +扩展到相关题目: +- 参数变化(四数之和) +- 条件变化(最接近的和) +- 返回值变化(返回索引而非值) + +## 改进后的模板 + +```markdown +# [题目名称] + +LeetCode [题号]. [难度] + +## 题目描述 +[题目原文] + +## 思路推导 + +### 暴力解法分析 +```python +[暴力解法代码] +``` +**时间复杂度**: O(?) +**问题**: [分析瓶颈] + +### 优化思考 +**观察**: [发现规律或可优化点] +**思路**: [优化方向] + +### 为什么这样思考? +1. [核心原理1] +2. [核心原理2] +3. [降维/转换思想] + +## 解题思路 + +### 核心思想 +[一句话总结] + +### 算法流程(详细版) + +**步骤1:[步骤名称]** +``` +[图解或示例] +``` +- 关键点1:[说明] +- 关键点2:[说明] + +**步骤2:[步骤名称]** +[...] + +### 关键细节说明 + +**细节1:[细节名称]** +```python +[代码示例] +``` +[为什么这样写] + +**细节2:[细节名称]** +[...] + +### 边界条件分析 + +**边界1:[条件名称]** +``` +输入:[示例] +输出:[示例] +处理:[说明] +``` + +### 复杂度分析(详细版) + +**时间复杂度**: +``` +[计算过程] +总计:O(?) +``` + +**空间复杂度**: +``` +[计算过程] +总计:O(?) +``` + +## 代码实现 + +```python +[完整代码,包含详细注释] +``` + +## 执行过程演示 + +``` +[示例输入的完整执行过程] +``` + +## 常见错误 + +### 错误1:[错误名称] +❌ 错误写法: +```python +[错误代码] +``` +✅ 正确写法: +```python +[正确代码] +``` +**原因**:[说明] + +## 变体问题 + +### 变体1:[变体描述] +[解法思路] + +## 总结 + +**核心要点**: +1. [要点1] +2. [要点2] +3. [要点3] + +**易错点**: +- [易错点1] +- [易错点2] +``` + +## 实施建议 + +1. **优先级**:先完善高频题目(Hot 100) +2. **分阶段**: + - 第一阶段:增加"思路推导"部分 + - 第二阶段:增加"执行过程演示" + - 第三阶段:增加"常见错误" + +3. **保持一致性**:所有题目使用统一模板 + +4. **可读性优先**: + - 使用代码块突出关键部分 + - 使用列表提高可读性 + - 适当使用emoji(谨慎使用) + +## 示例对比 + +查看 `三数之和-改进版.md` 了解改进后的完整效果。