最大子序列和 O(n)
我们用sum[i]来表示以arr[i]结尾的最大连续子序列和,则状态转移方程为:
int MaxSubsequenceSum( const int A[], int N )
{
int ThisSum, MaxSum, j;
ThisSum = MaxSum = 0;
for(j=0; j<N; j++)
{
ThisSum+= A[j];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
else if(ThisSum<0)
ThisSum=0;
}
return MaxSum;
}
最小子序列和 O(n) 原文
minsum的初始值是0 flag是标记数列中的某个子序列的和是否小于零(必要条件是存在负数)。否则就是不存在负数,那么返回的就是数组中的最小值。
#include<stdio.h>
#define MAXN 1000
int a[MAXN];
int n;
int minSubsequenceSum() {
int ThisSum, MinSum, i,min;
ThisSum = MinSum = 0;
int flag=0;
min = a[0];
for (i = 0; i < n; i++) {
ThisSum += a[i];
if (min > a[i])
min = a[i];
if (ThisSum < MinSum)
{
MinSum = ThisSum;
flag = 1;
}
else if (ThisSum>0)//任何正的子序列不可能是最小子序列的前缀
ThisSum = 0;
}
if (flag)
return MinSum;
else
return min;
}
int main() {
int i ;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
printf("%d", minSubsequenceSum());
}
最小正子序列和 O(n) 原文
将序列累计求和并存入数组,将数组排序,计算相邻两个值之差,若差大于0且在原数组中两数前后顺序相同,则记录下两数之差,遍历一遍新数组,若有符合条件的差小于前一个,则将最小差记录下来
#include<stdio.h>
//求最小正子序列和
//最小正子序列和:1、连续子序列,2、序列和为正且最小
//思路:求出开始的一组子序列:{-2},{-2,11},
//{-2,11,-4}, {-2,11,-4,13},{-2,11,-4,13,-5},{-2,11,-4,13,-5,-2}
//剩下的子序列必然可以通过上面的这一组子序列相减获得
//所以要获得最小正子序列各,必然将上面的序列和排序后的相邻序列和相减所得
//其他方法:究举所有子序列,与最大子序和方法相同,
//要记录秩
typedef struct node{
int value;
int rank;
}nodes;
//快排
int quickSort(nodes a[],int low,int high){
//int low=0,high=len-1;
nodes pivotkey=a[low];
while(low<high){
while(low<high&&a[high].value>=pivotkey.value) --high;
a[low]=a[high];
while(low<high&&a[low].value<=pivotkey.value) ++low;
a[high]=a[low];
}
a[low]=pivotkey;
return low;
}
//快排的递归
void Qsort(nodes a[],int low,int high){
if(low<high){
int temp=quickSort(a,low,high);
Qsort(a,low,temp);
Qsort(a,temp+1,high);
}
}
void getMin(int a[],int len){
nodes b[len];
int i;
//Item *tmp = new Item[len];
int sum=0;
for( i=0;i<len;i++){
//b[i]=(nodes)malloc(sizeof(node));
sum+=a[i];
b[i].value=sum;
b[i].rank=i;
}
//将其排序 O(nlogn)
Qsort(b,0,len-1);
//因为排序了最初子序列和的大小,min的计算只需要相邻子序列和相减计算
for(i=0;i<len;i++){
printf("%d rank为%d ",b[i].value,b[i].rank);
}
printf("\n");
int min=b[0].value>=0?b[0].value:b[len-1].value;
for(i=1;i<len;i++){
//必须得够减
if(b[i].rank>b[i-1].rank){
int temp=b[i].value-b[i-1].value;
if(temp>0&&temp<min){
min=temp;
}
}
}
printf("最小正序列和为:%d",min);
}
int main(){
int test[]={-2,11,-4,13,-5,-2};
getMin(test,sizeof(test)/sizeof(int));
}
最大子序列乘积 O(n) 原文
考虑存在负数的情况(ps:负负会得正),因此我们用两个辅助数组,max[i]和min[i],max[i]来表示以arr[i]结尾的最大连续子序列乘积,min[i]来表示以arr[i]结尾的最小连续子序列乘积,因此状态转移方程为:
and
#include <stdio.h>
#include <stdlib.h>
double maxNumInThree(double a, double b, double c)
{
double max;
max = (a > b) ? a : b;
max = (max > c) ? max : c;
return max;
}
double minNumInThree(double a, double b, double c)
{
double min;
min = (a < b) ? a : b;
min = (min < c) ? min : c;
return min;
}
int main(void)
{
int i, n;
double *arr, *max, *min, res;
while (scanf("%d", &n) != EOF) {
arr = (double *)malloc(sizeof(double) * n);
max = (double *)malloc(sizeof(double) * n);
min = (double *)malloc(sizeof(double) * n);
for (i = 0; i < n; i ++)
scanf("%lf", arr + i);
// 动态规划求最大连续子序列乘积
max[0] = min[0] = res = arr[0];
for (i = 1; i < n; i ++) {
max[i] = maxNumInThree(arr[i], max[i - 1] * arr[i], min[i - 1] * arr[i]);
min[i] = minNumInThree(arr[i], max[i - 1] * arr[i], min[i - 1] * arr[i]);
if (max[i] > res)
res = max[i];
}
if (res >= 0) {
// 判断是否为浮点数
if ((res - (int)res) == 0)
printf("%d\n", (int)res);
else
printf("%.2lf\n", res);
} else {
printf("-1\n");
}
free(arr);
}
return 0;
}