在求连续区间的最大和是一种动态规划的常见例题。
那么如何能快速求算得一个长度为n的数组的最大连续区间和?
第一反应当然是,通过暴力计算每一个区间的和进而求其最大值。
但时间复杂度到达了不可接受的O(n^2)...
而比较好的算法如下:
#include<iostream>
using namespace std;
#define ll long long
#define endl '\n'
//#include <bits/stdc++.h>
ll A[10003];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
//求连续区间最小:时间:O(n) 空间:O(n)
ll len, temp, ans = 0, dp = 0;
cin >> len;
for (int i = 0; i < len; ++i)
{
cin >> A[i]; //输入数组第i个值temp=Arr[i]
dp = max(A[i], A[i] + dp); //以Arr[i]结尾的区间最大值
ans = max(ans, dp);
}
cout << ans << endl;
/*
测试样例:
9
-3 8 -2 1 -6 8 1 0 -1
*/
}
显然,最大连续区间一定是以某个数为结尾的区间。
不妨假设以A[i]结尾的最大连续区间和为dp[i]。
那么,我们只需要遍历原数组,比较A[i]以及A[i]+dp[i-1].
(即,当dp[i-1]<0时,直接舍弃前面的区间,以A[i]做dp[i],反之连接上之前的区间即可)
再退一步想,如果不查找区间位置,好像并没有存储数组的必要...
此时直接用temp接受临时的A[i]即可。
#include<iostream>
using namespace std;
#define ll long long
#define endl '\n'
//#include <bits/stdc++.h>
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
//求连续区间最小:时间O(n) 空间O(1)
ll len, temp, ans = 0, dp = 0;
cin >> len;
for (int i = 0; i < len; ++i)
{
cin >> temp; //输入数组第i个值temp=Arr[i]
dp = max(temp, temp + dp); //以Arr[i]结尾的区间最大值
ans = max(ans, dp);
}
cout << ans << endl;
/*
测试样例:
9
-3 8 -2 1 -6 8 1 0 -1
*/
}
以上代码运用了动态规划的思想,通过求算Arr[i]结尾的区间最大值dp[i]的最大值为原数组Arr[i]的最大连续区间和。并且舍弃了原来的数组...所以它只能求和不能求区间的位置
#include<iostream>
using namespace std;
#define ll long long
#define endl '\n'
//#include <bits/stdc++.h>
ll A[10003];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
//求连续区间最小:时间:O(n) 空间:O(n)
ll len, temp, ans = 0, dp = 0, left, right = 0;
cin >> len;
for (int i = 0; i < len; ++i)
{
cin >> A[i]; //输入数组第i个值temp=Arr[i]
dp = max(A[i], A[i] + dp); //以Arr[i]结尾的区间最大值
if (dp > ans)
{
ans = dp; //更新答案以及右区间
right = i;
}
}
cout << ans << endl;
for (int i = right; i >= 0; --i)//寻找左区间位置
{
ans -= A[i];
if (ans == 0)
{
left = i;
break;
}
}
cout << "最大连续区间为: [ " << left << " , " << right << " ]\n";
/*
测试样例:
9
-3 8 -2 1 -6 8 1 0 -1
*/
}
以上通过存储数组来查找区间位置:
当然,除了动态规划的方法还有分治等方法,但总的来说dp便于理解。
文章制作不易,有不对的还望斧正。