九度 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\n",num1, index, num2); cout << max(num1, num2) << endl; } return 0; }