计蒜客_最大子阵列
主要用到的思想:
对于数组A[1..n],如果已知其子数组A[1..j]的最大子阵列,则可以在常数时间内获取A[1..j+1]的最大子数组,具体思路如下:A[1..j+1]的最大子数组(记为max_j+1),要么(不包含A[j+1])(即,A[1..j]的最大子数组(记为max_j)),要么是包含的A[j+1]的局部最大子数组(暂时叫做maybeMax_j+1)。
前一种情况容易获取,对于第二种情况,假设可以维护一个包含A[j]的A[1..j]的最大子数组的值(暂时叫做 maybeMax_j),那么包含A[j+1]的A[1..j+1]的最大子数组(暂时叫做maybeMax_j+1)要么是A[j+1]+maybeMax_j,要么是 A[j+1],证明如下:
可以将maybeMax_j+1分为两类包含包含maybeMax_j的和不包含maybeMax_j的。
(1)对于包含A[1..j]中元素的情况,
假设,maybeMax_j为A[k..j],for any k'(k' != k,1<=k'<=j),A[k'..j]<Ak..j,也即是A[k..j]+A[j+1]>A[k'..j]+A[j+1],所以包含A[1..j]中元素的maybeMax_j+1待选项为Ak..j+1;
(2)不包含A[1..j]中元素的情况,
即,A[j+1];
对于两种情况的选择,即代码中的if (a[i] + maybeMax > a[i]).
对于A[1..j+1]的max_j+1,要么是maybeMax_j+1,要么是max_j,对于两种情况的选择,即代码中if (maybeMax > max).
具体变量所指所指如图:
由此可知,由maybeMax_j经过常数时间可以得出maybeMax_j+1;进一步,由max_j可以在常数时间得出max_j+1;
初始情况下,易得,max_j=A[1],maybeMax_j=A[1].
整个算法时间复杂度为O(n).具体代码如下:
#include<iostream>
using namespace std;
int getAns(int *a, int len) {
int maybeMax = a[0];
int max = a[0];
for (int i = 1; i < len; ++i) {
if (a[i] + maybeMax > a[i]) {
maybeMax = a[i] + maybeMax;
}
else {
maybeMax = a[i];
}
if (maybeMax > max) {
max = maybeMax;
}
}
return max;
}
void maxSubArray() {
int a[1000];
int n;
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
cout<<getAns(a, n)<<endl;
}
int main()
{
maxSubArray();
return 0;
}
算法导论分治法那一章,使用分治法,时间复杂度为 \(O(n\lg n)\).并且课后有相似习题,介绍了上面的这种方法。
实现代码