最大子序列和的问题:
就是给出一组数据,求出里面那几个前后连续的数的和最大。
书中给出4个算法,时间复杂度从O(N^3)降到O(N^2)再降到O(NlogN)最后到O(N),这就是人家跑完程序都走上人生巅峰了,你面对一组数据苍颜白发却还在等待结果...
//O(N^3)
int maxSubSum1(const vector
& a)
{
int maxSum = 0;
for (int i = 0; i < a.size(); ++i)
for (int j = i; j < a.size(); ++j)
{
int thisSum = 0;
//这个for其实就是多余写出来...
for (int k = i; k <= j; ++k)
thisSum += a[k];
if (thisSum > maxSum)
maxSum = thisSum;
}
return maxSum;
}
//O(N^2) 优化的就是上一个算法里的for
int maxSubSum2(const vector
& a)
{
int maxSum = 0;
for (int i = 0; i < a.size(); ++i)
{
int thisSum = 0;
for (int j = i; j < a.size(); ++j) {
thisSum += a[j];
if (thisSum > maxSum)
maxSum = thisSum;
}
}
return maxSum;
}
//分治法O(NlogN)
int maxSumRec(const vector
&a, int left, int right)
{
if (left == right)//只有一个元素
if (a[left] > 0)
return a[left];
else
return 0;
int center = (left + right) / 2;
int maxLeftSum = maxSumRec(a, left, center);
int maxRightSum = maxSumRec(a, center + 1, right);
int maxLeftBorderSum = 0, leftBorderSum = 0;
for (int i = center; i >= left; --i)
{
leftBorderSum += a[i];
if (leftBorderSum > maxLeftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
int maxRightBorderSum = 0, rightBorderSum = 0;
for (int j = center + 1; j <= right; ++j)
{
rightBorderSum += a[j];
if (rightBorderSum > maxRightBorderSum)
maxRightBorderSum = rightBorderSum;
}
int maxSum1 = maxLeftSum > maxRightSum ? maxLeftSum : maxRightSum;
return max(maxSum1, maxLeftBorderSum + maxRightBorderSum);
}
int maxSubSum3(const vector
&a)
{
return maxSumRec(a, 0, a.size() - 1);
}
//O(N)逆天了
int maxSubSum4(const vector
&a) {//任何负值不可能是最大子序列的开头 int maxSum = 0, thisSum = 0; for (int i = 0; i < a.size(); ++i) { thisSum += a[i]; if (thisSum > maxSum) maxSum = thisSum; else if (thisSum < 0) thisSum = 0; } return maxSum; } int main() { vector
a = { 4,-3,5,-2,-1,2,6,-2 }; cout << maxSubSum1(a) << endl; cout << maxSubSum2(a) << endl; cout << maxSubSum3(a) << endl; cout << maxSubSum4(a) << endl; system("pause");
算法4是许多聪明算法的典型,它只对数据进行一次扫描,一旦a[i]被读入并被处理,就不再需要被记忆。在任意时刻,算法都能对它已经读入的数据给出子序列问题的正确答案。
(联机算法(on-line algorithm),ps:仅需要常量空间并以线性时间与线性时间运行的算法几乎是完美的算法,我不造哦~)
有了最大子序列和的问题就有了
最小子序列和,
照葫芦画瓢,好的算法你不用,我也很绝望啊~
int minSubSum4(const vector
&a)
{
int minSum = 0, thisSum = 0;
for (int i = 0; i < a.size(); ++i)
{
thisSum += a[i];
if (thisSum < minSum)
minSum = thisSum;
else if (thisSum > 0)
thisSum = 0;
}
return minSum;
}
然后是
最小正子序列和:
我成为我渣了,只想到了O(N^2)...
int main()
{
vector
a = { 4,-3,5,-2,-1,2,6,-2 };
//如下为算法
int minSum = a[0];
for (int i = 0; i != a.size(); ++i) {
int thisSum = 0;
for (int j = i; j != a.size(); ++j) {
thisSum += a[j];
if (minSum > thisSum && thisSum > 0)
minSum = thisSum;
}
}
cout << minSum;
system("pause");
}
具体是 对累计的和排序,然后对应出索引,找出可以成为序列的索引即可,注意对于相同的大小数据索引要一致
struct item {
int index;
int value;
};
bool cmp(item &a, item &b)
{//相同的值,让其索引为小的,否则就不是之比较相邻两个数的索引那么简单了
if (a.value == b.value)
a.index = b.index = a.index < b.index ? a.index : b.index;
return a.value < b.value;
}
void minPSubSum(const vector
&a)
{
vector
b;
item temp;
int thisSum = 0;
//所选序列为(x,y]
temp.index = 0;
temp.value = 0;
b.push_back(temp);
for (size_t i = 0; i < a.size(); ++i)
{
thisSum += a[i];
temp.value = thisSum;
temp.index = i+1;
b.push_back(temp);
}
sort(b.begin(), b.end(), cmp);
int minPSum = b.rbegin()->value;
for (size_t j = 0; j < b.size() - 1; ++j)
{
if (b[j].index < b[j + 1].index)
{
thisSum = b[j + 1].value - b[j].value;
if (thisSum < minPSum)
minPSum = thisSum;
}
}
cout << minPSum<
a = { 4,-3,5,-2,-1,2,6,-2 };
vector
b = { 4, 0, 4, 1, -1 };
minPSubSum(a);
minPSubSum(b);
system("pause");
}
最大子序列乘积:
这个是没想出来,但是看到了这个公式,就秒懂了,瞬间感触也很多,对自己渣,对别人的强,以及那么多时间的停滞不前
i=1 --->>size()-1
max(a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]);
min (a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]);
int max(int a, int b, int c)
{
int max = a;
if (b > max)max = b;
if (c > max)max = c;
return max;
}
int min(int a, int b, int c)
{
int min = a;
if (b < min)min = b;
if (c < min)min = c;
return min;
}
void maxPlus(const vector
&a)
{
int maxValue= a[0];
vector
maxArray;
maxArray.push_back(maxValue);
vector
minArray{ maxArray };
for (size_t i = 1; i < a.size(); ++i)
{
//算法的精髓
maxArray.push_back(max(a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]));
minArray.push_back(min(a[i], maxArray[i - 1] * a[i], minArray[i - 1] * a[i]));
if (maxArray.back() > maxValue)
maxValue = maxArray.back();
}
cout << maxValue << endl;
}
int main()
{
vector
a = { 4,-3,5,-2,-1,2,6,-2 };
vector
b = { 4, 0, 4, 1, -1 }; maxPlus(a); maxPlus(b); system("pause"); }
to be continue!!!