最大子序列和问题

1.递归

该方法由书上提供,比较好理解:给定一个数组,从中间划分成两个数组[1,mid],[mid+1,end];最大子序列可分为三种情况:

a.位于左半边

b.位于右半边

c.跨越两边

求两边最大子序列时可递归求解,求跨越两边的子序列时分别从mid、mid+1出发,求得left_sum和right_sum,相加即为跨越两边的最大子序列和。时间复杂度O(nlogn)。

代码:

#include <stdio.h>
#include <stdlib.h>

int Find_Mid_Max(int* q,int start,int end) {
    int mid = (start + end) / 2;
    int left_sum = 0;
    int right_sum = 0;
    int sum = 0;
    int i;
    for (i = mid;i > 0;i--) {
        sum += q[i];
        if (sum > left_sum)
            left_sum = sum;
    }
    sum = 0;
    for (i = mid+1;i <=end;i++) {
        sum += q[i];
        if (sum > right_sum)
            right_sum = sum;
    }
    return left_sum + right_sum;
}

int Find_Max(int* q, int start, int end) {
    int maxsum = 0;
    if (start == end) {
        if (q[end] > maxsum)
            maxsum = q[end];
        return maxsum;
    }
    int mid = (start + end) / 2;
    int left=Find_Max(q, start, mid);
    int right = Find_Max(q, mid + 1, end);
    int across = Find_Mid_Max(q, start, end);
    if (left > right && left > across)
        maxsum = left;
    else if (right > across)
        maxsum = right;
    else
        maxsum = across;
    return maxsum;
}

int main() {
    int k;
    if (scanf("%d", &k) == 0){}
    int* q = (int*)malloc(sizeof(int) *(k+1));
    int i;
    for (i = 1;i <= k;i++) {
        if(scanf("%d",&q[i])==0){}
    }
    int max=Find_Max(q, 1, k);
    printf("%d", max);
    return 0;
}

 2.在线处理

从第一个元素开始遍历整个数组,用tempsum暂时记录当前子序列的和。如果加上一个元素之后,tempsum<0了,那么包含这个元素再继续往后加的子序列一定不可能是最大的,因为负数总是对这个子序列产生消极的影响,所以我们可以舍弃这个序列,从下一个序列开始再次寻找。用maxsum记录最大值,若tempsum>maxsum则更新。还要记录最大子序列的开始和结束点(具体见代码,有些地方是题目里要求的)。时间复杂度O(n)。

代码:

#include <stdio.h>
#include <stdlib.h>

int* Find_Max(int* q, int start, int end) {
    int *ret=(int *)malloc(sizeof(int)*3);
    ret[0] = 0;//记录最大和
    ret[1] = start;//开始下标
    ret[2] = 0;//结束下标           
    int tempsum = 0;
    int temps = 0;
    int i;
    int neg = 0;
    int pos = 0;
    int zer = 0;
    for (i = 0;i < end;i++)  {
        if (q[i] > 0)
            pos = 1;
        if (q[i] < 0)
            neg = 1;
        if (q[i] == 0)
            zer = 1;
        tempsum += q[i];
        if (tempsum < 0) {
            tempsum = 0;
            temps = i + 1;
        }
        else {
            if (tempsum > ret[0]) {
                ret[0] = tempsum;
                ret[1] = q[temps];
                ret[2] = q[i];
            }
        }
    }
    if (!pos&&neg&&!zer) {
        ret[1] = q[start];
        ret[2] = q[end-1];
    }
    else if (!pos && neg && zer) {
        ret[1] = start;
        ret[2] = 0;
    }
    return ret;
}

int main() {
    int k;
    if (scanf("%d", &k) == 0){}
    int* q = (int*)malloc(sizeof(int) *k);
    int i;
    for (i = 0;i < k;i++) {
        if(scanf("%d",&q[i])==0){}
    }
    int *ret=Find_Max(q, 0, k);
    printf("%d %d %d", ret[0],ret[1],ret[2]);
    return 0;
}
原文地址:https://www.cnblogs.com/yaotong0830/p/14192648.html