PTA动态规划实战:从最大子段和到背包问题,5个经典题目详解(附Java代码)
如果你正在准备算法竞赛或者技术面试,动态规划(Dynamic Programming, DP)这道坎儿,大概率是绕不过去的。我刚开始接触DP的时候,感觉它就像个黑盒子,状态转移方程看得人云里雾里,明明每个字都认识,连起来却不知道在说什么。直到后来在PTA(Programming Teaching Assistant)平台上刷了几十道题,从最简单的最大子段和一路磕磕绊绊到复杂的区间DP,才慢慢摸到了一点门道。我发现,与其去死记硬背那些晦涩的理论,不如直接动手,把几个最经典、最常考的题目吃透,理解其背后的“状态”是如何定义和转移的。这篇文章,我就想和你分享这趟实战之旅中的五个关键“驿站”,它们覆盖了线性DP、背包、序列处理、区间规划等核心场景。我会用详细的Java代码和一步步的推理,帮你把PTA上这些经典题目的“筋骨”拆解清楚,让你下次再遇到DP问题时,心里能有个清晰的解题框架,而不是一片空白。
1. 最大子段和:动态规划的“入门仪式”
最大子段和问题,常被称作动态规划最好的“入门仪式”。它的描述极其简单:给定一个可能包含负数的整数序列,找出其中连续子序列的最大和。如果所有整数都是负数,那么最大和定义为0。题目要求时间复杂度为O(n),这直接排除了暴力枚举所有子序列的O(n²)或O(n³)解法,暗示我们必须用更聪明的方式。
为什么它能用动态规划解决? 关键在于我们如何定义“状态”。一个最自然的想法是:dp[i] 表示“以第 i 个元素结尾的”所有连续子序列中,和最大的那个值。注意这个定义,它固定了子序列的终点,这样我们就能利用之前计算的结果。
提示:在动态规划中,对状态的定义往往决定了递推关系的难易。将状态定义为“以i结尾”而非“从i到j”,是简化问题的关键一步。
那么,dp[i] 怎么从之前的状态推导出来呢?对于以 arr[i] 结尾的子序列,只有两种可能:
- 它单独构成一个子序列,和就是
arr[i]。 - 它接在以
arr[i-1]结尾的最大和子序列后面,和是dp[i-1] + arr[i]。
我们的目标是和最大,所以取两者中的较大值:dp[i] = max(arr[i], dp[i-1] + arr[i])。
这个递推关系就是整个算法的核心。我们只需要遍历一次数组,不断更新 dp[i],同时用一个变量记录所有 dp[i] 中的最大值,即为最终答案。
import java.util.Scanner;
public class MaxSubArraySum {
public static int maxSubSum(int[] arr) {
if (arr == null || arr.length == 0) {
return 0;
}
int currentMax = arr[0]; // 相当于dp[i-1],初始为第一个元素
int globalMax = arr[0]; // 记录全局最大值
for (int i = 1; i < arr.length; i++) {
// 状态转移:currentMax = max(arr[i], currentMax + arr[i])
currentMax = Math.max(arr[i], currentMax + arr[i]);
// 更新全局最大值
globalMax = Math.max(globalMax, currentMax);
}
// 根据题意,如果全局最大值小于0,则返回0
return globalMax > 0 ? globalMax : 0;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
System.out.println(maxSubSum(arr));
scanner.close();
}
}
这段代码是上述思路的空间优化版本。我们注意到,在计算 dp[i] 时,只依赖于 dp[i-1],因此不需要保存整个 dp 数组,用一个变量 currentMax 滚动更新即可。空间复杂度从O(n)降到了O(1)。PTA上的样例输入 -2 11 -4 13 -5 -2,计算过程如下表所示:
| i | arr[i] | currentMax (更新前) | currentMax (更新后) | globalMax |
|---|---|---|---|---|
| 0 | -2 | - |

1万+

被折叠的 条评论
为什么被折叠?



