1. 题目背景与核心考察点解析
"3.04 oj基础116 117 118"这个编号序列指向的是在线判题系统(Online Judge)中一组基础算法练习题。这类题目通常作为编程初学者的入门训练,重点考察对基础数据结构和算法的掌握程度。从编号规律来看,这三题很可能属于同一知识模块的递进训练。
提示:OJ系统中的基础题库往往按照"同一知识点由浅入深"的方式编排,建议按编号顺序依次攻克。
1.1 典型题型特征分析
基础题库的116-118题通常具有以下特征:
- 116题:单一知识点的直接应用(如数组遍历)
- 117题:增加一个维度的复杂度(如嵌套循环)
- 118题:引入简单算法思想(如贪心或模拟)
根据多年刷题经验,这类题目最常见的考察方向包括:
- 数组元素操作(查找、排序、统计)
- 字符串处理(反转、分割、匹配)
- 简单数学问题(质数、公约数、数列)
1.2 解题通用方法论
面对基础OJ题目时,建议采用以下解题框架:
- 输入输出分析:明确数据输入格式和预期输出形式
- 边界条件确认:考虑空输入、极值等特殊情况
- 暴力解法构思:先实现最直观的解决方案
- 复杂度优化:分析时间/空间复杂度改进空间
2. 题目116详解与实现方案
2.1 题目还原与需求拆解
假设116题是典型的数组求和问题,具体要求可能是:
"给定整数数组nums和目标值target,求数组中两数之和等于target的索引组合"
核心考察点:
- 数组遍历能力
- 哈希表快速查找
- 边界条件处理
2.2 双循环暴力解法
python复制def twoSum(nums, target):
for i in range(len(nums)):
for j in range(i+1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
return []
时间复杂度:O(n²)
空间复杂度:O(1)
2.3 哈希表优化方案
python复制def twoSum(nums, target):
hashmap = {}
for i, num in enumerate(nums):
complement = target - num
if complement in hashmap:
return [hashmap[complement], i]
hashmap[num] = i
return []
时间复杂度:O(n)
空间复杂度:O(n)
注意:哈希解法需要处理重复元素的情况,测试用例如[3,3] target=6
3. 题目117进阶解析
3.1 题目升级模式推演
117题通常会在116题基础上增加约束条件,例如:
- 输入数组变为已排序状态
- 要求找出所有可能的组合而不仅是一组
- 结果不能包含重复三元组
假设题目为:"在有序数组中找出所有不重复的三元组,使a+b+c=0"
3.2 双指针技巧实现
python复制def threeSum(nums):
nums.sort()
res = []
for i in range(len(nums)-2):
if i > 0 and nums[i] == nums[i-1]:
continue
l, r = i+1, len(nums)-1
while l < r:
s = nums[i] + nums[l] + nums[r]
if s < 0:
l += 1
elif s > 0:
r -= 1
else:
res.append([nums[i], nums[l], nums[r]])
while l < r and nums[l] == nums[l+1]:
l += 1
while l < r and nums[r] == nums[r-1]:
r -= 1
l += 1
r -= 1
return res
关键技巧:
- 排序预处理(时间复杂度O(nlogn))
- 外层循环固定第一个元素
- 内层使用双指针寻找匹配对
- 跳过重复元素保证结果唯一性
4. 题目118高阶应用
4.1 题目复杂度提升
118题往往会引入更复杂的条件,例如:
- 组合元素数量增加到四个
- 目标值变为最接近而非严格相等
- 加入元素使用次数限制
假设题目为:"找出数组中四个数之和等于target的所有唯一四元组"
4.2 递归回溯解法
python复制def fourSum(nums, target):
def kSum(nums, target, k):
res = []
if len(nums) == 0 or nums[0] * k > target or nums[-1] * k < target:
return res
if k == 2:
return twoSum(nums, target)
for i in range(len(nums)):
if i == 0 or nums[i-1] != nums[i]:
for subset in kSum(nums[i+1:], target-nums[i], k-1):
res.append([nums[i]] + subset)
return res
nums.sort()
return kSum(nums, target, 4)
def twoSum(nums, target):
res = []
l, r = 0, len(nums)-1
while l < r:
s = nums[l] + nums[r]
if s < target or (l > 0 and nums[l] == nums[l-1]):
l += 1
elif s > target or (r < len(nums)-1 and nums[r] == nums[r+1]):
r -= 1
else:
res.append([nums[l], nums[r]])
l += 1
r -= 1
return res
算法特点:
- 通用化kSum解决方案
- 递归分解问题规模
- 排序+剪枝优化效率
- 时间复杂度O(n^(k-1))
5. 调试技巧与测试用例设计
5.1 通用测试用例模板
| 测试类型 | 输入样例 | 预期输出 | 验证要点 |
|---|---|---|---|
| 基础案例 | [2,7,11,15], 9 | [0,1] | 基本功能 |
| 无解情况 | [1,2,3], 7 | [] | 空结果处理 |
| 重复元素 | [3,3], 6 | [0,1] | 哈希冲突 |
| 负数值 | [-1,-2,-3], -5 | [1,2] | 符号处理 |
| 边界值 | [INT_MAX,1], INT_MIN | [] | 整数溢出 |
5.2 常见错误排查
-
数组越界:
- 检查循环终止条件是否包含等号
- 确认递归时的数组切片范围
-
结果重复:
- 排序后检查相邻元素去重
- 使用集合类型临时存储结果
-
时间超限:
- 检查是否存在多重循环冗余
- 使用哈希替代线性查找
-
内存溢出:
- 避免不必要的中间变量存储
- 大数组使用生成器而非列表
6. 算法优化进阶路线
6.1 时间复杂度的演进路径
- 暴力枚举法:O(n^k)
- 排序+双指针:O(n^(k-1))
- 哈希缓存法:O(n^(k-1))但空间换时间
- 位运算压缩:适用于特殊约束条件
- 动态规划:当问题具有最优子结构时
6.2 空间优化技巧
-
原地操作:
- 直接在输入数组上修改
- 使用数组索引代替新建结构
-
延迟计算:
- 只在必要时生成结果
- 使用yield返回生成器
-
位图压缩:
- 用bit位表示状态
- 适用于有限集合操作
在实际刷题过程中,建议先写出可工作的代码,再逐步进行优化。我个人的经验是,先用暴力解法通过测试,再分析性能瓶颈所在,这样比一开始就追求最优解更有效率。