題目地址:
https://www.lintcode.com/problem/continuous-subarray-sum/description
給定一個數組,求其最大和連續子列,返回區間起點和終點下標。若有若干不同區間和都是最大,則返回字典序最小的那兩個下標組合。
回顧最大和連續子列不需要返回端點下標,只需返回和,這一問題的做法。若以表示以結尾的連續子數組中的最大和,那麼顯然這裏並不需要用一個數組來記錄,只需要用一個變量記錄即可,隨着遍歷數組更新之。此外我們需要時時記錄sum
對應的區間兩端點,同時發現更大的和的時候,把這兩個端點更新到結果了即可。代碼如下:
import java.util.ArrayList;
import java.util.List;
public class Solution {
/*
* @param A: An integer array
* @return: A list of integers includes the index of the first number and the index of the last number
*/
public List<Integer> continuousSubarraySum(int[] A) {
// write your code here
List<Integer> res = new ArrayList<>();
if (A == null || A.length == 0) {
return res;
}
res.add(0);
res.add(0);
// start和end維護當前sum對應區間的兩個端點,
// sum維護以A[i]結尾的最大子區間的和,maxSum維護已經發現的最大子區間和
int start = 0, end = 0;
int sum = A[0], maxSum = A[0];
for (int i = 1; i < A.length; i++) {
// sum >= 0說明以A[i]結尾的最大和要將前面的sum連上去;
// 否則說明以A[i]結尾的最大和的區間就是A[i]自己
// 注意,如果sum = 0則說明A[i]可以連上前面的區間也可以不連,但爲了字典序較小,應該選擇不連
// start和end時時刻刻維護sum對應區間的兩個端點
if (sum >= 0) {
sum += A[i];
end = i;
} else {
sum = A[i];
start = end = i;
}
// 發現更大的和,更新已發現的最大和並更新端點
if (sum > maxSum) {
maxSum = sum;
res.set(0, start);
res.set(1, end);
}
}
return res;
}
}
時間複雜度,空間。
關於爲什麼start
和end
維護了sum
對應區間的兩個端點,可以由數學歸納法得到。此處省略證明。