53. Maximum Subarray

20170706

今天再做這題,寫出來(lái)了。這題之前說(shuō)的「局部最優(yōu)解」「全局最優(yōu)解」可以這么理解,局部最優(yōu)解就相當(dāng)于dp[i-1],因?yàn)槲覍懲陿?biāo)準(zhǔn)dp后很容易發(fā)現(xiàn)這個(gè)dp其實(shí)只需要知道前一位的狀態(tài),所以就用個(gè)int來(lái)滾動(dòng)就行了,這個(gè)int就是所謂的局部最優(yōu)解。然后之前說(shuō)的局部最優(yōu)解必須包含當(dāng)前數(shù)字,其實(shí)就是因?yàn)檫@題要求的是連續(xù)的subarray。

//標(biāo)準(zhǔn)
    public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (dp[i - 1] > 0) {
                dp[i] = dp[i - 1] + nums[i];
            } else {
                dp[i] = nums[i];
            }
            max = Math.max(max, dp[i]);
        }
        return max;
    }
//滾動(dòng)
    public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        int curMax = nums[0];
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (curMax > 0) {
                curMax = curMax + nums[i];
            } else {
                curMax = nums[i];
            }
            max = Math.max(curMax, max);
        }
        return max;
    }

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

一道easy題,一月份的時(shí)候做的,現(xiàn)在再做又一時(shí)想不起來(lái)了。。這題是DP的思想,但是有很多種思路;最近看了code ganker的一些題目很多都用到了「局部最優(yōu)解」「全局最優(yōu)解」這個(gè)概念,比如Jump GameBest Time to Buy and Sell Stock等。

這種思想的核心是,「局部最優(yōu)解」local表示「必須包含當(dāng)前一步操作」時(shí)候的最優(yōu)解,全局最優(yōu)解global就是代表全局最優(yōu)解,每步比較local和global。

State transition equation:

dp[i] = dp[i-1] >0 ? dp[i-1] + nums[i] : nums[i]

這題的方程,要注意是根據(jù)dp[i-1] >0的正負(fù)來(lái)判斷,跟nums[i]無(wú)關(guān)。
第二點(diǎn),由于「局部最優(yōu)解」local表示「必須包含當(dāng)前一步操作」時(shí)候的最優(yōu)解,所以這題dp數(shù)組的最后一位不能代表最優(yōu)結(jié)果,而是要維護(hù)的global。

因?yàn)橹恍枰耙粋€(gè)位置的值,所以這道題可以狀態(tài)壓縮,可以這么寫:

    public int maxSubArray(int[] nums) {
        if (nums.length == 0) return 0;
        int local = nums[0];
        int global = nums[0];
        //local[i] = local[i-1] < 0 ? nums[i]: local[i-1]+nums[i]

        for (int i = 1; i < nums.length; i++) {
            local = local > 0 ? local + nums[i] : nums[i];
            global = Math.max(local, global);
        }
        return global;
    }

有時(shí)候我想不通為什么需要比較局部和最優(yōu),原因就是局部因?yàn)橐?dāng)前的值所以有一定局限性。比如這道題,如果test case是一串負(fù)數(shù),那global的作用就顯而易見(jiàn)了。

我昨天有個(gè)疑問(wèn),是不是所以DP都需要用到一個(gè)數(shù)組保存狀態(tài),空間換時(shí)間嘛。事實(shí)上不是的,有些題目只需要用到之前一個(gè)子狀態(tài),或者可以用空間輪換,就不需要數(shù)組。比如,利用常規(guī)路子,這題還可以這樣寫

public int maxSubArray(int[] A) {
        int n = A.length;
        int[] dp = new int[n];//dp[i] means the maximum subarray ending with A[i];
        dp[0] = A[0];
        int max = dp[0];
        
        for(int i = 1; i < n; i++){
            dp[i] = A[i] + (dp[i - 1] > 0 ? dp[i - 1] : 0);
            max = Math.max(max, dp[i]);
        }
        
        return max;
}

本質(zhì)上,dp[i]就相當(dāng)于local。


另外這題還有一種divide and conquer做法,挺復(fù)雜的先不討論了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容