leetcode *1186. 刪除一次得到子數組最大和

【題目】*1186. 刪除一次得到子數組最大和

53.最大子序和
*152. 乘積最大子數組
*1186. 刪除一次得到子數組最大和
*1191. K 次串聯後最大子數組之和

給你一個整數數組,返回它的某個 非空 子數組(連續元素)在執行一次可選的刪除操作後,所能得到的最大元素總和。
換句話說,你可以從原數組中選出一個子數組,並可以決定要不要從中刪除一個元素(只能刪一次哦),(刪除後)子數組中至少應當有一個元素,然後該子數組(剩下)的元素總和是所有子數組之中最大的。
注意,刪除一個元素後,子數組 不能爲空。
請看示例:

示例 1:

輸入:arr = [1,-2,0,3]
輸出:4
解釋:我們可以選出 [1, -2, 0, 3],然後刪掉 -2,這樣得到 [1, 0, 3],和最大。

示例 2:

輸入:arr = [1,-2,-2,3]
輸出:3
解釋:我們直接選出 [3],這就是最大和。

示例 3:

輸入:arr = [-1,-1,-1,-1]
輸出:-1
解釋:最後得到的子數組不能爲空,所以我們不能選擇 [-1] 並從中刪去 -1 來得到 0。
     我們應該直接選擇 [-1],或者選擇 [-1, -1] 再從中刪去一個 -1。

提示:
1 <= arr.length <= 10^5
-10^4 <= arr[i] <= 10^4

【解題思路1】“最大子數組和“動態規劃變型

maxOfEnd: 以第i個元素爲結尾的最大子數組和
maxLastButOne: 以第i-1個元素爲結尾的最大子數組和
maxDelOne: 以第i個元素結尾,但刪除至多一個元素的最大子數組和
maxSoFar: 返回值,取整個遍歷過程中maxDelOne的最大值
轉移方程:要麼刪除第i-1個元素但不刪除i-1之前的任何元素,要麼直接繼承第i-1個元素的maxDelOne(包含不刪除任何元素的情況),要麼只取第i個元素本身。

class Solution {
    public int maximumSum(int[] arr) {
        int maxLastButOne = 0;
        int maxDelOne, maxOfEnd, maxSoFar;
        maxDelOne = maxOfEnd = maxSoFar = arr[0];
        for (int i = 1; i < arr.length; i++) {
            int moe = maxOfEnd;
            maxOfEnd =  Math.max(moe + arr[i], arr[i]);
            maxDelOne = Math.max(arr[i], Math.max(maxLastButOne + arr[i], maxDelOne + arr[i]));
            maxSoFar =  Math.max(maxSoFar, maxDelOne);
            maxLastButOne = moe;
        }
        return maxSoFar;
    }
}

【解題思路2】兩個dp數組分別考察刪除和不刪除

定義f ( i ) 和 g ( i ),其中 f( i ) 表示不刪除元素的情況下最大子數組和(區間爲[0,i]),g( i ) 代表刪除元素的情況下的最大子數組和(區間爲[0,i])。

  • f(i) = Math.max(f(i-1)+arr[i],arr[i]) ,要麼是當前元素累加之前的和,要麼是重新從當前元素開始
  • g(i) = Math.max(g(i-1)+arr[i],f(i-1))
    要麼是加上當前元素,也就是維持之前刪除某個元素的情形,即g[i-1]+arr[i]
    要麼是刪除當前這個元素,那麼區間[0, i-1]就是不刪除元素的情況,即f(i-1)+0(注意是f不是g!!)
class Solution {
    public int maximumSum(int[] arr) {
        int len = arr.length;
        int[] f = new int[len];
        int[] g = new int[len];
        f[0] = arr[0];
        g[0] = -200001;
        int res = Math.max(f[0], g[0]);
        for(int i=1;i<len;i++){
            f[i] = Math.max(f[i-1]+arr[i],arr[i]);//其實就是f(i-1)是否<0
            g[i] = Math.max(g[i-1]+arr[i],f[i-1]);
            res = Math.max(res,Math.max(f[i],g[i]));
        }
        return res;
    }
}

二維數組
dp[i][j]表示以arr[i]結尾的,已經刪除j次的子數組最大值
dp[i][j] = Math.max(dp[i - 1][j] + arr[i],dp[i - 1][j - 1]);

  • 不刪除arr[i], dp[i - 1][j] + arr[i]
  • 刪除arr[i],dp[i - 1][j - 1]
class Solution {
    public int maximumSum(int[] arr) {
        int n = arr.length;
        int k = 1;
        int max = arr[0];
        int[][] dp = new int[n][k + 1];
        //init
        dp[0][0] = arr[0];
        for(int i = 1; i < n; i++){
            dp[i][0] = Math.max(dp[i - 1][0] + arr[i],arr[i]);
            max = Math.max(max,dp[i][0]);
        }
        //dp
        for(int i = 1; i < n; i++){
            for(int j = 1; j <= k; j++){
                dp[i][j] = Math.max(dp[i - 1][j] + arr[i],dp[i - 1][j - 1]);
                max = Math.max(max,dp[i][j]);
            }
        }
        
        return max;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章