面試現場:連續子陣列的最大和
題目
輸入一個整型陣列,數組裡有正數也有負數。陣列中一個或連續的多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間複雜度為O(n)。
舉例
輸入:2, -3, 4, 5, -9
輸出:9
和最大的連續子陣列是 {4, 5},結果就是9。
思路
我們先假設和最大連續子陣列是從第一個數開始的。初始化和為0。第一步是加上數字2,此時和為2。第二步加上數字-3,此時和為-1。那麼問題來了,我們到底要不要加上數字-3呢?分析過程如下:
- 加上-3。此時的和為-1,然後由-1繼續加下一個數。
- 不加-3。也就是意味當前連續子陣列就終結於-3之前的數字,下一個連續子陣列的和初始化為0,再加上第一個數字-3,和為-3。
由上述分析可知,加上-3,此時累加的子陣列和是-1;不加-3,此時累加的子陣列和是-3。-1大於-3,為了後續的累加和更大,所以選擇加上-3。
接下來,第三步要不要加上數字4,我們依據上面的決策流程繼續分析。當加上數字4,此時累加和為4-1=3;不加上數字4,意味著當前連續子陣列終結於數字4之前,此時的累加和初始化為0,加上數字4後和等於4。顯而易見,4大於3,所以我們選擇拋棄前面的累加和,由數字4繼續開始。
後續步驟省略,總結一番。當我們遍歷陣列時,對於每個數字,要麼與前面的子陣列累加,要麼作為新子陣列的起點,如果累加之後的子陣列和小於(或等於)當前數字,我們就選擇拋棄前面的累加和,將當前數字作為新子陣列的起點。整個過程可以用表格總結如下:
步驟 | 操作 | 累加的子陣列和 | 最大的子陣列和 |
---|---|---|---|
1 | 加2 | 2 | 2 |
2 | 加-3 | -1 | 2 |
3 | 拋棄累加的和-1,加4 | 4 | 4 |
4 | 加5 | 9 | 9 |
5 | 加-9 | 0 | 9 |
程式碼
根據題目要求,我們只需要求出連續子陣列的最大和,如果面試官還要求找到連續子陣列的起點與終點下標,那麼最終的java程式碼如下:
public class Main { public static int child_sum(int[] arr) { if (arr == null || arr.length < 1) { return 0; } int left0 = 0; int left1 = 0; int right = 0; int max = arr[0]; int sum = 0; for (int i = 0; i < arr.length; i++) { sum += arr[i]; if (sum <= arr[i]) { //使用<=還是<呢? sum = arr[i]; left0 = i; } if (sum > max) { max = sum; left1 = left0; right = i; } } System.out.println("left:" + left1 + " right:" + right + " max:" + max); return max; } public static void main(String[] args) { int[] arr1 = new int[]{2, -3, 4, 5, -9}; int[] arr2 = new int[]{2, -2, 4, 5, -9}; int[] arr3 = new int[]{-2, -3, -4, -5, -9}; child_sum(arr1); child_sum(arr2); child_sum(arr3); } }
列印輸出:
left:2 right:3 max:9
left:2 right:3 max:9
left:0 right:0 max:-2
在上面的程式碼中使用小於等於或者使用小於有什麼區別呢?
假設陣列為{2, -2, 4, 5, -9},如果判斷條件是小於等於當前數字,那麼所得的最大連續子陣列為{4, 5}。如果判斷條件是小於當前數字,那麼所得的最大連續子陣列為{-2, 2, 4, 5}。如果對最大連續子陣列的長度沒有明確要求,使用小於等於進行判斷即可