聲明:
作者不是什麼大佬,只是想寫寫算法,提高一下自己的內功。所以代碼可能會非常凌亂,(大佬們就當個笑話看就可以了),但我會認真註釋。
最後如果有路過的大佬,希望可以留下你們的建議和看法,謝謝!
42. 面試題連續子數組的最大和
一、原題鏈接
二、題目介紹
輸入一個整型數組,數組裏有正數也有負數。數組中的一個或連續多個整數組成一個子數組。求所有子數組的和的最大值。
本題中有個額外要求:
時間複雜度爲O(n)。
三、測試用例
1.示例
輸入: nums = [-2,1,-3,4,-1,2,1,-5,4]
輸出: 6
解釋: 連續子數組 [4,-1,2,1] 的和最大,爲 6。
2.提示
- 1 <= arr.length <= 10^5
- -100 <= arr[i] <= 100
四、思路解析
這道題算是比較簡單的動態規劃的題。如果不知道什麼是動態規劃,可以到這個知乎回答上瞅一眼。什麼是動態規劃
本題目要求連續子數組的最大和,如果牽扯到最大,此處我們可以通過求出關於i上每一個位置的最大連續數組的值,最終比較取最大值就可以了。
核心:怎麼求當前位置上的最大值。
當遍歷到i的時候,我們默認有一個之前的最優解是dp[i-1],比如:i=2的時候,dp[1]=a1;i=3,dp[2]=a1+a2(a1和a2都大於0的時候)。
那麼我們可以默認dp[i]=dp[i-1]+ai。
但我們要記得本體讓求的是最大子集的和,因此如果出現 dp[i-1]+ai<ai(dp[i-1]<0)的時候,我們認爲i位置的最大就是ai本身了。
根據上述邏輯可以列出方程dp(i) = max(a[i], dp(i-1)+a[i])
五、代碼
這道動態規劃題,按照動態規劃的解決方式仍然不需要知道實現的路徑是什麼,只要求結果即可。
根據上面的分析:當要添加第i個位置的數據nums[i],需要判斷前面 i-1的最優解+nums[i] 與 nums[i]的大小。
- 如果小,就說明本次最優解從i開始
- 如果大,就說明本次最優解可以繼續延續上一次的最優解進行解題(我們不用管這次最優解是否比上次的最優解更高,因爲我們求出所有最優解之後可以通過比較獲取最大的解)
public int maxSubArray(int[] nums) {
int max = 0; //當前最大的最優解
// 沒有必要保存每個位置的最優解,在求出最優解的同時直接與當前最大值比較即可
int last = 0; //上次的最優解
// 從左到右遍歷
for (int i = 0; i < nums.length; i++) {
// 獲取默認的dp[i]
int temp = last + nums[i];
// 判斷dp[i]與ai的大小,並把此位置的最優解更新上去
last = temp >= nums[i] ? temp : nums[i];
// 邊界問題,如果是第一個位置直接就是最大
if(i==0){
max = last;
}else {
// 把當前的最大值與此處的最優解進行比較,如果大就替換
max = last >= max ? last : max;
}
}
return max;
}