本文最后更新于 2024年6月7日 下午
题目:
给定一个长度为 n 的整形数组 nums,求从数组索引 l 至 索引 r 的整数序列中,连续序列和的最大值为多少。
思路:
本题的主要思路,可分为两种
- 使用遍历的思想,遍历出序列的每种情况,逐一求和,计算最大值
但这种思路及其耗费时间,不可取。
- 使用动态规划的思想,使用一个数组 dp 记录,从索引 l 起包含位置 k 连续序列和的最大值 (l<=k<=r),最大值可由下面的公式推导。
dp[k] = max{ num[k] , num[k] + dp[k-1] }
公式解释:
- 这个公式的意思很明了,即某个位置之前的序列和若为正,那么包含之前的序列,肯定会使包含当前位置的序列和增大。
- 这个公式不好理解之处在于,若一个位置的值为负还要包括他吗?举个例子来说明:
- 若位置 i 处值为负,之前序列和为正,那么虽然包括了他使到这个位置为止的序列和减小,但是起到了连接 i+1 位置的作用,若 i+1 位置的值很大,那么包含 i 位置使序列和减小的损失就可以忽略了,因为到 i+1 处的序列和是增大的了。
- 若之前序列和为负,那么包含之前序列就没有任何意义,到 i 位置的序列和的最大值,就是位置 i 的值。
- 数组 dp 中记录的是包含位置 i 后的序列的最大值,那么在将所有位置进行计算后,取 dp 数组中的最大值,即是整个序列中子序列和的最大值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <iostream> #include <vector> #include <algorithm>
using namespace std;
int main() { int n; cin >> n; vector<int> nums(n + 1); vector<int> max_sum(n + 1);
for (int i = 1; i <= n; ++i) { cin >> nums[i]; }
int l, r, sum; cin >> l >> r;
sum = nums[l] = max_sum[l]; for (int j = l + 1; j <= r; ++j) { max_sum[j] = max(nums[j], nums[j] + max_sum[j - 1]); if (sum < max_sum[j]) sum = max_sum[j]; } cout << sum << endl;
return 0; }
|
优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream> #include <vector> #include <algorithm>
using namespace std;
int main() { int n; cin >> n; vector<int> nums(n + 1);
for (int i = 1; i <= n; ++i) { cin >> nums[i]; } int l, r, sum, result;
cin >> l >> r;
result = sum = nums[l];
for (int j = l; j <= r; ++j) { sum = max(nums[j], sum + nums[j]); result = max(result, sum); } cout << result << endl;
return 0; }
|