【LeetCode】劍指DP:53. Maximum Subarray 最大子串和

一、概述

Easy題,吉跋貓Easy。這題我想了一個半小時沒想出,只好投降。看了半天看明白了DP的原理,還有遞歸和分治,這倆懶得看了。服了服了,先看DP吧。實在是有點難。

Discuss區一個老哥的抱怨是我內心的真實寫照:

hhhhh還是自己太菜了。

二、分析

我最開始看:Easy題麼,應該不難。美滋滋開始分析遞推關係:

嗯,假設我現在輸入的是123,它是和最大的子串,下一個,下一個要是正數,就放裏,不是正數,就不放裏。

這不就是遞推公式嘛。是個屁,假設下一個是-1,下下一個是3,那麼怎麼辦?-1要放裏,不放不是根據正負來的。

正的一定放裏,負的可能放裏可能不放。所以我這算個屁的遞推關係。

那找不到遞推關係。這時怎麼辦?

自己手寫一下所有的結果。

如下:

來看一下這些值都是怎麼算出來的:

-2,第一個,所以最大子串和爲-2;

1,我把-2和1比較,1大,所以最大子串和爲1;

-3,1-3=-2,-2小於1,所以最大子串和還是1;

4,1-3+4=2,2大於1,最大子串和是2麼?不是,4自己更大,最大子串和爲4;

-1,4-1=3,3小於4,所以最大子串和還是4;

2,4-1+2=5,5大於4,最大子串和爲5;

1,4-1+2+1=6,6大於5,最大子串和爲6;

-5,4-1+2+1-5=1,1小於6,所以最大子串和還是6;

4,4-1+2+1-5+4=5,5小於6,所以最大子串和還是6。

輸出6。

好像有點眉目了。看上面可以看出一個規律:好像把原來的數組分成了若干個小數組。爲什麼這樣呢?

我們來想一下,對於一個數組,找一個子數組,要求左端固定,其和在所有子數組中最大。怎麼找?既然左端固定,那就遍歷原數組,一個一個加入子數組裏面,加完之後看和是否變大,維護一個變量儲存最大值就可以。也就是說,對於一個左端固定的子數組,找和最大子數組很簡單。

現在的問題是,左端不是固定的,它可以隨意變——真的可以隨意變麼?我們再來觀察上面推出結果的過程,子數組的左端變化過程爲-2→1→4,最左端就變了三次。在最左端不變時,問題就退化成了上面的問題。

因此問題變成了最左端什麼時候會變?-2,1,4,這些數字有什麼共性?

-2組成的數組是第一個,它欽定是最左端的,不用看它。

爲什麼1能代替-2成爲最左端的呢?因爲1加上它前面的-2比1小啊。加還不如不加,那就不加,只留下1。

還是不清楚。再看4,爲什麼4能代替1呢?因爲“1-3+4=2”,而2又比4小,我們換一下,4加上前面的1-3比4小啊。加還不如不加,那就不加,只留下4。

有點眉目了,是不是“對於一個正數,如果它前面的子串和小於0,那麼‘加還不如不加’,然後左端點就移動到新的正數”,是這樣麼?

如果上面說的是對的,那麼將原數組分割成多個小數組的分隔點,就是滿足上面條件的正數了。

嗯?存不存在這樣一種情況:比如說我的部分子串是1和10,現在到10了,發現前面子串和爲負數,所以從10開始,但是實際上從10左邊的1開始更好?

不存在。爲什麼呢?因爲1也是一個正數啊,從10開始的前提是前面子串和爲負數,那麼對於1來說,它的前面子串和也是負數,因此在1的時候,左端點就移動到1了,對於10來說,不存在前面是1而且前面子串和是負數的情況。

然後在子串裏,在左端點沒有移動的時候,就加上一個元素,更新max,最後最終的max就是結果。

我覺得這不是一道典型的DP題,它沒有直觀的遞推公式,或者需要這樣說,它的遞推公式不能直接求出結果,求出結果還需要另外一步。

代碼如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int tmp=nums[0];
        int res=tmp;
        for(int i=1;i<nums.size();++i)
        {
            tmp=nums[i]+(tmp>0?tmp:0);
            res=max(res,tmp);
        }
        return res;
    }
};

tmp負責更新當前子串的和,當遇到一個正數的時候,若當前子串的和爲負數,tmp變爲這個正數【這個操作等價於子數組的左端點改變】;若當前子串的和爲正數,那麼直接加進去;如果遇到負數,那麼直接加進去。然後更新tmp的最大值。所以DP是針對“當前子串的和”進行DP,不是針對“子串的最大和”進行DP。

三、總結

算是我寫的最難的Easy題了。

這道題教會了我做DP的一個思路:如果DP沒法直接求出結果,而且這個結果是一個最值,那麼可以用DP求這個結果的所有值,每次求完之後更新最值。

更重要的,如果對一道題沒思路,就手寫出自己做出結果的整個過程,算法就隱藏在過程裏。

 

 

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