1. 题目背景与核心考察点
OJ95-97这三道题目作为2026年2月21日的编程练习,属于典型的算法竞赛训练题集。这类题目通常具有几个共同特征:明确的输入输出规范、严格的时间空间限制、隐藏的边界条件测试用例。根据多年刷题经验,这类编号连续的题目往往存在递进关系——可能是同一类问题的不同变种,也可能是难度阶梯式上升的同类解法。
提示:遇到连续编号题目时,建议先快速浏览所有题目描述,往往能发现命题者暗藏的解题线索
从题目编号推测,OJ95很可能考察基础数据结构应用,OJ96会引入动态规划或贪心算法,而OJ97通常是前两题的进阶版,可能需要组合多种算法思想。这种出题模式在ACM-ICPC区域赛和LeetCode周赛中非常常见。
2. 题目分析与解法思路
2.1 OJ95基础解法
这道题描述为"给定n个整数的数组,找出所有满足a+b=c的三元组"。最直观的暴力解法是三层循环枚举所有可能组合:
python复制def find_triplets(arr):
res = []
n = len(arr)
for i in range(n):
for j in range(i+1, n):
for k in range(j+1, n):
if arr[i] + arr[j] == arr[k]:
res.append((arr[i], arr[j], arr[k]))
return res
但这样的时间复杂度是O(n³),当n=1000时就需要10^9次运算,必然超时。优化方向有两个:
- 预处理哈希表:用字典存储所有元素,将第三层循环转化为O(1)查找
- 先排序再双指针:排序后利用有序特性减少无效比较
2.2 OJ96进阶优化
题目升级为"找出所有不重复的三元组,且需要考虑不同顺序视为相同"。这要求:
- 对结果去重
- 优化时间复杂度到O(n²)
经过多次测试验证,最稳定的解法是:
python复制def find_unique_triplets(arr):
arr.sort()
res = set()
n = len(arr)
for i in range(n):
target = -arr[i]
left, right = i+1, n-1
while left < right:
s = arr[left] + arr[right]
if s == target:
res.add((arr[i], arr[left], arr[right]))
left += 1
right -= 1
elif s < target:
left += 1
else:
right -= 1
return list(res)
这个解法有几点关键:
- 先排序保证元素有序(O(nlogn))
- 外层循环固定第一个元素
- 内层使用双指针寻找匹配对
- 用集合自动处理重复结果
2.3 OJ97的终极挑战
最终题目变为"在OJ96基础上,要求输出三元组的索引而非值,且索引顺序i<j<k"。这带来两个新难点:
- 需要保留原始索引信息
- 比较条件变得更复杂
经过多次尝试,最终采用的结构化处理方案:
python复制def find_index_triplets(arr):
indexed_arr = [(val, idx) for idx, val in enumerate(arr)]
indexed_arr.sort()
res = []
n = len(indexed_arr)
for i in range(n):
if i > 0 and indexed_arr[i][0] == indexed_arr[i-1][0]:
continue
target = -indexed_arr[i][0]
left, right = i+1, n-1
while left < right:
s = indexed_arr[left][0] + indexed_arr[right][0]
if s == target:
res.append(sorted([
indexed_arr[i][1],
indexed_arr[left][1],
indexed_arr[right][1]
]))
left += 1
while left < right and indexed_arr[left][0] == indexed_arr[left-1][0]:
left += 1
elif s < target:
left += 1
else:
right -= 1
return res
3. 性能对比与测试数据
3.1 时间复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 暴力枚举 | O(n³) | O(1) | 仅适用于n<100 |
| 哈希优化 | O(n²) | O(n) | 通用解法 |
| 双指针法 | O(n²) | O(1) | 已排序数据 |
3.2 边界测试用例设计
- 空数组输入:[]
- 预期输出:[]
- 全零数组:[0,0,0,0]
- 预期输出:[(0,0,0)]
- 无解数组:[1,2,3]
- 预期输出:[]
- 大数测试:[1000000000, -1000000000, 0]
- 需检查整数溢出
- 重复元素:[1,1,1,2,2]
- 需验证去重逻辑
4. 调试技巧与常见错误
4.1 典型错误模式
-
忘记处理输入排序
- 症状:部分测试用例通过但随机测试失败
- 修复:在算法开头添加arr.sort()
-
索引与值混淆
- 症状:OJ97输出结果值正确但索引错误
- 修复:使用(index, value)元组保存原始位置
-
去重逻辑不完整
- 症状:输出包含重复三元组
- 修复:在外层循环添加跳过重复元素的判断
4.2 调试日志示例
在开发OJ97解法时,可以添加临时打印语句验证中间结果:
python复制print(f"i={i}, val={indexed_arr[i]}, target={target}")
print(f"left={left}, right={right}, sum={indexed_arr[left][0]+indexed_arr[right][0]}")
5. 算法扩展与应用
这类"三元组求和"问题是许多实际应用的简化模型:
- 金融领域的组合投资分析
- 化学中的分子结构匹配
- 游戏开发中的碰撞检测优化
在工业级实现中还需要考虑:
- 流式数据处理(无法一次性加载全部数据)
- 分布式计算(海量数据分片处理)
- 近似算法(允许一定误差换取更高性能)
对于想继续深入的同学,推荐研究:
- 3SUM问题的线性决定树模型
- 基于位运算的优化方案
- 量子计算环境下的算法重构