根据前面文章所提到的最大子序列和https://blog.csdn.net/weixin_41223818/article/details/80573351
接下来对其拓展,说说最小子序列和、最小正子序列和、最大子序列乘积的解法
最小子序列和
这个问题可以直接模仿最大子序列和的联机算法,改一下判断条件即可
int MinSubsequenceSum (const int A[], int N)
2 {
3 int ThisSum, MinSum;
4 ThisSum = MinSum = 0;
5
6 for(int i = 0; i != N; ++i){
7 ThisSum += A[i];
8 if(MinSum > ThisSum)
9 MinSum = ThisSum;
10 else if(ThisSum > 0)
11 ThisSum = 0;
12 }
13 return MinSum;
最小正子序列和
即连续子序列和要大于零,且要最小
这个问题感觉模仿上面的联机算法已经行不通了,因为没法确定何时将ThisSum重置为0,所以只能模仿最大子序列和的O(N^2)算法与O(NlogN)的算法.
1.O(N^2)
//用两个循环遍历所有情况
for (int i = 0; i != N; ++i) {
ThisSum = 0;
for (int j = i; j != N; ++j) {
ThisSum += A[j];
if (MinSum > ThisSum && ThisSum > 0)
MinSum = ThisSum;
}
}
2.O(NlogN)
这里的思路与最大子序列和有所不同
假设序列为 4,-1,5,-2,-1,2,6,-2
先求一下从第一位开始的到第i位的累加,最前面加上0(一个都不选的情况)
4,-1,5,-2,-1,2,6,-2 => 0 4 3 8 6 5 7 13 11
对这个累加的数列排个序,0 3 4 5 6 7 8 11 13,并记录对应的下标0 2 1 5 4 6 3 8 7,然后只要判断邻近的两个数是否可以组成序列,比如4和3就不可以,因为4 > 3而4对应下标为1,3对应为2。4和5就可以,4对应下标1,5对应下标5,这样的话,从第1个数到第4个数,就组成了一个和为1的序列。
解释一下为什么只需检查相邻2个数就可以,设ABC是排序后的结果,如果A同B不能组成序列,而A同C可以组成序列,那么B同C也可以组成序列,并且BC会是一个更优的解。
排序的时候处理一下,数字相等的话可以合并成1个元素,只记录索引的最大最小值就可以。
#include <iostream>
#include <algorithm>
#include <string.h>
struct Item {
int value;
int index;
};
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;
}
int MinSubsequenceSum (const int A[], int N)
{
int ThisSum = 0, MinSum = 0;
Item* B = new item[N];
memset(B, 0, sizeof(Item) * N);
for (int i = 0; i < N; ++i) {
B[i].index = i;
ThisSum += A[i];
B[i].value = ThisSum;
}
std::sort(B, B+N, cmp);
MinSum = B[0].value > 0 ? B[0].value : 2<<29;
for (int i = 1; i < N; ++i) {
if ((B[i-1].index < B[i].index) && (B[i].value - B[i-1].value > 0) && (B[i].value - B[i-1].value < MinSum))
{
MinSum = B[i].value - B[i-1].value;
}
}
delete[] B;
return MinSum;
}
int main ()
{
int A[8] = {4,-1,6,-2,-1,3,6,-2}; // 4, 0, 4, 1, -1
std::cout << MinSubsequenceSum(A, 8);
return 0;
}
最大子序列乘积
思路:
以元素i结尾序列提供的最大正数记做 pos, 最小负数记做 nag
a[n] 大于零时:
pos[n] = max{pos[n-1] * a[n], a[n]}
max_value = max{max_value, pos[n]}
若n-1位置存在最小负数, 更新 nag[n] = nag[n-1] * a[n]
a[n] 小于零时:
pos[n] = max{nag[n-1] * a[n], 0.0}
max_value = max{max_value, pos[n]}
更新 nag[n] = min{pos[n-1] * a[n], a[n]}
a[n] 等于零时:
清空 nag[n] 与 pos[n]
#include <iostream>
inline double max(const double& a, const double& b)
{
return (a > b) ? a : b;
}
double MaxSubsequenceProduct(double a[], int len)
{
double Max = 0.0, pos = 0.0, old = 0.0, nag = 1.0;
for (int i = 0; i < len; ++i) {
if (a[i] > 1e-6) {
pos = max(old * a[i], a[i]);
Max = max(Max, pos);
if (nag < -1e-6) {
nag *= a[i];
}
}
else if (a[i] < -1e-6) {
pos = max(0.0, nag * a[i]);
Max = max(Max, pos);
nag = (old * a[i] > a[i]) ? a[i] : old * a[i];
}
else {
nag = 1.0; pos = 0.0;
}
old = pos;
}
return Max;
}
int main()
{
double a[7] = { -2.5, 4, 0, 3, 0.5, 8, -1 };
std::cout << MaxSubsequenceProduct(a, 7);
std::cin >> a[2];
return 0;
}