九度 1527:首尾相连数组的最大子数组和

题目描述:

给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的。数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],…arr[n-1],arr[0],…,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选)

思路

1. 本以为这题与 Leetcode 上 Gas Station 一样, 提交之后也能通过 2 个 case, 但最终通过一组数据 (2 1 -3 2) 决定了 Gas Station 的做法不正确

2. 分两种情况讨论, (1) 假设最大连续子数组不相连那么用dp解法即可. (2) 假设最大连续子数组相连, 那么肯定有一个负数, 这个最大连续子数组不包含它, 这个负数就是数组中最小连续子数组的末尾(它不一定是最小的, 比如 -2 -1). 那么我们从这个末尾的下一位开始使用方法(1)计算首位相连的情况. 返回(1)(2)的较大值

代码

#include <iostream>
#include <stdio.h>
using namespace std;

int val[250000];

int maxseq(int a, int b) {
    int global = 0, local = 0;
    for(int i = a; i < b; i ++) {
        local = max(val[i], local+val[i]);
        global = max(local, global);
    }
    return global;
}

int minindex(int n) {
    int global = 0x7f7f7f7f, local = 0x7f7f7f7f, index = -1;
    for(int i = 0; i < n; i ++) {
        local = min(local+val[i], val[i]);
        if(local < global) {
            index = i;
            global = local;
        }
    }
    return index;
}

int main() {
    int n;
    while(scanf("%d", &n) != EOF) {
        bool hasneg = false;
        int rev = 0;
        for(int i = 0; i < n; i ++) {
            scanf("%d", val+i);
            if(val[i] < 0) hasneg = true;
            rev += val[i];
        }
        if(!hasneg) {
            cout << rev << endl;
            continue;
        }

        // has negtive numbers
        int num1 = maxseq(0, n);
        int index = minindex(n);
        for(int i = n; i < 2*n; i ++)
            val[i] = val[i-n];
        int num2 = maxseq(index+1, index+1+n);

        //printf("%d %d %d
",num1, index, num2);
        cout << max(num1, num2) << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xinsheng/p/3581046.html