假设大家都已经写过这道题的原题——最大连续子序列和,我们知道递推方程为 dp[i] = max(nums[i], dp[i - 1] + nums[i])。若 dp[i] = nums[i],说明新起了一段序列;若 dp[i] = dp[i - 1] + nums[i],说明延续了之前序列。
如何找到开始下标:在求 dp[i] 的过程中,如果新起了一段序列,那么就说明这是一个潜在的子序列,应该把它的开始下标记录下来。然而,这个子序列并不一定是最大的,因此我们使用变量 t 临时记录该下标,如果等到最后,发现这个子序列是最大的,那才把 t 赋给 firstIndex 作为答案。
如何找到结束下标:在求 dp[i] 的过程中,如果求得的 dp[i] 把 ans 更新了(意味着该段序列最大),那么就把 i 赋值给 lastIndex 作为答案。
代码(很容易读懂):
#include <iostream> #include <cstdio> using namespace std; const int MAXN = 10005; int nums[MAXN]; int dp[MAXN]; int main() { int n; while (scanf("%d", &n) != EOF) { if (n == 0) { break; } bool allNegative = true; for (int i = 0; i < n; i++) { scanf("%d", &nums[i]); if (nums[i] >= 0) { allNegative = false; } } if (allNegative) { printf("0 %d %d\n", nums[0], nums[n - 1]); continue; } dp[0] = nums[0]; int ans = dp[0], firstIndex = 0, lastIndex = 0, t = 0; for (int i = 1; i < n; i++) { if (nums[i] > dp[i - 1] + nums[i]) { // 新起一段序列 dp[i] = nums[i]; t = i; } else { // 延长之前序列 dp[i] = dp[i - 1] + nums[i]; } // 如果把ans更新了,才真正找到了满足题意的最大连续子序列 if (dp[i] > ans) { ans = dp[i]; firstIndex = t; lastIndex = i; } } printf("%d %d %d\n", ans, nums[firstIndex], nums[lastIndex]); } return 0; }