1. 东华OJ18~21题目解析与实战指南
作为一名在算法竞赛领域摸爬滚打多年的老选手,我深知OJ平台题目对编程能力提升的重要性。东华大学的在线判题系统(OJ)18~21题是经典的算法训练序列,涵盖了基础数据结构与算法的核心考点。这些题目看似简单,但暗藏玄机,很多选手在这里踩过坑。今天我就带大家深度拆解这组题目,分享我的解题思路和实战技巧。
这四道题目的设计非常巧妙,从字符串处理到动态规划,难度梯度合理。18题考验基础编码能力,19题引入简单算法思想,20题需要数据结构应用,21题则上升到综合问题解决层面。我在大二时第一次刷这组题,前后花了整整一周时间才全部AC(Accepted),期间经历了无数次WA(Wrong Answer)和TLE(Time Limit Exceeded)。现在回头看,这些题目确实是算法入门的最佳试金石。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 题目18:字符串处理基础
2.1 题目描述与核心考点
题目18通常要求实现特定字符串操作,比如统计字符出现次数、字符串反转或特定模式匹配。这类题目看似简单,但考察的是对编程语言字符串处理的熟练程度和边界条件处理能力。
以我遇到的一个版本为例:给定一个字符串,统计其中每个数字字符('0'-'9')出现的次数,按数字升序输出结果。输入保证只包含ASCII字符,长度不超过1000。
2.2 解题思路与实现
最直接的解法是使用长度为10的数组作为计数器:
python复制def count_digits(s):
cnt = [0] * 10
for ch in s:
if ch.isdigit():
cnt[int(ch)] += 1
return cnt
但这里有几个易错点:
- 字符判断要用isdigit()而非直接比较ASCII值
- 数组下标转换要准确(int(ch)而非ord(ch))
- 输出格式要严格匹配要求(空格分隔/换行等)
实战经验:在OJ系统中,10%的WA是因为输出格式不符。建议先仔细阅读输出要求,用样例进行完整测试。
2.3 性能优化技巧
当字符串长度达到1e6量级时,需要考虑优化:
- 在Python中,直接迭代字符串比先转换为list更快
- 使用collections.defaultdict可以简化代码但会稍慢
- C++中getchar()逐字符读取比cin更快
3. 题目19:简单算法应用
3.1 问题建模与分析
题目19通常引入基础算法思想,如贪心、枚举或简单递归。典型题目可能是找零钱问题:给定面额和金额,求最少硬币数。
例如:硬币面额为[1,5,10,20,50,100],金额为n(n≤1000),求最少硬币数。
3.2 贪心算法实现
贪心策略是每次取最大面额:
python复制def min_coins(n):
coins = [100, 50, 20, 10, 5, 1]
count = 0
for coin in coins:
count += n // coin
n %= coin
return count
3.3 边界情况处理
贪心算法在这组面额下成立,但需要注意:
- 金额为0时应输出0
- 如果面额不满足贪心性质(如[1,3,4]和6),需要改用DP
- 输入数据可能有多个测试用例,要正确处理输入循环
4. 题目20:数据结构应用
4.1 题目典型场景
题目20往往需要栈、队列或哈希表等数据结构。经典问题是括号匹配:给定一个括号序列,判断是否合法。
进阶版可能要求输出所有不匹配的位置,如:
输入: (a(b(c)d)
输出: 位置1的左括号未匹配
4.2 栈的完美应用
python复制def check_parentheses(s):
stack = []
mismatch = []
for i, ch in enumerate(s):
if ch == '(':
stack.append(i)
elif ch == ')':
if stack:
stack.pop()
else:
mismatch.append(i)
mismatch += stack
return sorted(mismatch)
4.3 调试技巧
这类题目容易犯的错误包括:
- 混淆字符索引从0还是1开始
- 未处理栈中剩余的左括号
- 输出顺序不符合要求
建议的调试方法:
- 先用简单用例测试(如"()"、"("、")")
- 打印中间状态(栈内容)
- 检查边界条件(空字符串、全左括号等)
5. 题目21:动态规划入门
5.1 问题抽象与定义
题目21通常是经典的DP问题,如斐波那契数列、爬楼梯或简单背包问题。以"最大子数组和"为例:
给定整数数组nums,找出具有最大和的连续子数组(至少包含一个元素),返回其和。
5.2 DP状态转移方程
定义dp[i]为以nums[i]结尾的最大子数组和:
code复制dp[i] = max(nums[i], dp[i-1] + nums[i])
max_sum = max(dp)
Python实现:
python复制def max_subarray(nums):
dp = [0] * len(nums)
dp[0] = nums[0]
for i in range(1, len(nums)):
dp[i] = max(nums[i], dp[i-1] + nums[i])
return max(dp)
5.3 空间优化技巧
观察到dp[i]只依赖前一个状态,可以优化空间:
python复制def max_subarray(nums):
max_sum = curr_sum = nums[0]
for num in nums[1:]:
curr_sum = max(num, curr_sum + num)
max_sum = max(max_sum, curr_sum)
return max_sum
5.4 常见错误分析
- 初始化错误:dp[0]应为nums[0]而非0
- 全负数数组:最大和不是0而是最大的负数
- 更新顺序:先更新curr_sum再更新max_sum
6. 实战调试与提交技巧
6.1 测试用例设计
针对不同题型要设计特色测试用例:
- 字符串:空串、全空格、极端长度
- 算法题:边界值、有序/无序输入
- DP问题:全正数、全负数、混合情况
6.2 OJ提交注意事项
- 语言选择要正确(Python3 vs Python2)
- 不要包含调试输出
- 输入处理要完整(while True try-except)
- 时间复杂度要预估(Python通常1e6次操作/秒)
6.3 性能优化策略
当遇到TLE时:
- 改用更快的输入方式(sys.stdin)
- 减少不必要的计算和存储
- 尝试更优算法(如O(nlogn)替代O(n²))
- 考虑用C++重写关键部分
7. 学习路线建议
刷完这组题目后,建议继续深入:
- 字符串:KMP、Trie、AC自动机
- 贪心:区间调度、霍夫曼编码
- 栈/队列:单调栈、双端队列应用
- DP:背包问题、状态压缩、树形DP
我个人的经验是,每道题目AC后要总结:
- 这道题考察什么知识点?
- 我的解法是最优的吗?
- 哪些边界情况没想到?
- 有没有更优雅的实现?
这样的刻意练习,进步会非常快。记住OJ刷题不在数量而在质量,把每道经典题目吃透,比盲目刷几百题更有价值。
