【Lintcode】402. Continuous Subarray Sum

題目地址:

https://www.lintcode.com/problem/continuous-subarray-sum/description

給定一個數組,求其最大和連續子列,返回區間起點和終點下標。若有若干不同區間和都是最大,則返回字典序最小的那兩個下標組合。

回顧最大和連續子列不需要返回端點下標,只需返回和,這一問題的做法。若以f[i]f[i]表示以A[i]A[i]結尾的連續子數組中的最大和,那麼顯然f[i+1]=max(f[i]+A[i+1],A[i+1])f[i+1]=\max(f[i]+A[i+1],A[i+1])這裏並不需要用一個數組來記錄f[i]f[i],只需要用一個變量記錄即可,隨着遍歷數組更新之。此外我們需要時時記錄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;
    }
}

時間複雜度O(n)O(n),空間O(1)O(1)

關於爲什麼startend維護了sum對應區間的兩個端點,可以由數學歸納法得到。此處省略證明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章