- Continuous Subarray Sum II
Given an circular integer array (the next element of the last element is the first element), find a continuous subarray in it, where the sum of numbers is the biggest. Your code should return the index of the first number and the index of the last number.
If duplicate answers exist, return any of them.
Example
Example 1:
Input: [3, 1, -100, -3, 4]
Output: [4, 1]
Example 2:
Input: [1,-1]
Output: [0, 0]
Challenge
O(n) time
这题如果没有想到正确思路的话很难。
我开始的想法还是基于Continuous Subarray Sum求出从0到2n-1的长度<=n的最大非空子数组,但是试了一下不容易。关键是这里添加了一个条件长度<=n。
比如说输入数组为[3,1,-3,4],扩展后得到[3,1,-3,4,3,1,-3,4]。如果不加长度限制,显然整个长度为8的整个数组就是最大非空子数组。但加了长度限制后,应该是[4,3,1]为最大非空子数组。但是到4的时候,sum>0,很难确定要从4开始。另一种办法是用2重循环,i=0…n, j=1…n,但是会超时。
解法1:
思路如下(参考九章): 先按照Continuous Subarray Sum求出无环情况下的最大非空子数组和S1。再用类似方法求出无环情况下的最小非空子数组和S2。答案即为max{S1, total_sum – S2}
注意:
- 特殊情况:如果选择了最小非空子数组而它是整个数组,说明所有A[i]都是负数,那么选取最大的A[i],其在求S1的时候就已经得到。
代码如下:
class Solution {
public:
/*
* @param A: An integer array
* @return: A list of integers includes the index of the first number and the index of the last number
*/
vector<int> continuousSubarraySumII(vector<int> &A) {
int n = A.size();
if (n == 0) return vector<int>();
int sum = A[0], maxSum = A[0], minSum = A[0], totalSum = A[0];
int maxStartIndex = 0, maxEndIndex = 0;
int gMaxStartIndex = 0, gMaxEndIndex = 0;
int minStartIndex = 0, minEndIndex = 0;
int gMinStartIndex = 0, gMinEndIndex = 0;
for (int i = 1; i < n; ++i) {
totalSum += A[i];
if (sum < 0) {
sum = A[i];
maxStartIndex = i;
maxEndIndex = i;
} else {
sum += A[i];
maxEndIndex = i;
}
if (sum > maxSum) {
maxSum = sum;
gMaxStartIndex = maxStartIndex;
gMaxEndIndex = maxEndIndex;
}
}
sum = A[0];
for (int i = 1; i < n; ++i) {
if (sum > 0) {
sum = A[i];
minStartIndex = i;
minEndIndex = i;
} else {
sum += A[i];
minEndIndex = i;
}
if (sum < minSum) {
minSum = sum;
gMinStartIndex = minStartIndex;
gMinEndIndex = minEndIndex;
}
}
if (maxSum > totalSum - minSum) {
return vector<int>{gMaxStartIndex, gMaxEndIndex};
} else {
if (gMinStartIndex == 0 && gMinEndIndex == n - 1) {
int maxElem = INT_MIN;
int maxElemIndex = 0;
for (int i = 0; i < n; ++i) {
if (maxElem < A[i]) {
maxElem = A[i];
maxElemIndex = i;
}
}
return vector<int>{maxElemIndex, maxElemIndex};
} else {
return vector<int>{(gMinEndIndex + 1) % n, (gMinStartIndex - 1 + n) % n};
}
}
}
};