【線性 dp】B011_LC_刪除一次得到子數組最大和(分類討論 / 空間壓縮)

一、Problem

給你一個整數數組,返回它的某個 非空 子數組(連續元素)在執行一次可選的刪除操作後,所能得到的最大元素總和。

換句話說,你可以從原數組中選出一個子數組,並可以決定要不要從中刪除一個元素(只能刪一次哦),(刪除後)子數組中至少應當有一個元素,然後該子數組(剩下)的元素總和是所有子數組之中最大的。

注意,刪除一個元素後,子數組 不能爲空。

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

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

二、Solution

方法一:dp

  • 定義狀態
    • f[i][0]f[i][0] 表示以 a[i]a[i] 結尾且沒刪過元素的子數組最大總和
    • f[i][1]f[i][1] 表示以 a[i]a[i] 結尾且刪除過元素的子數組最大總和
  • 思考初始化:
    • f[0][0]=a[0]f[0][0] = a[0]
    • f[0][1]=0f[0][1] = 0
  • 思考狀態轉移方程
    • f[i][0]=max(f[i1][0]+a[i],a[0])f[i][0] = max(f[i-1][0] + a[i], a[0]) 要麼接着前一段,要麼新開一段。
    • f[i][1]=max(f[i1][1]+a[i],f[i1][0])f[i][1] = max(f[i-1][1] + a[i], f[i-1][0]) 要麼接着前一段;要麼刪除 a[i]a[i] 就此斷開。
  • 思考輸出max(f[0...n)[0],f[0...n)[1])max(f[0...n)[0], f[0...n)[1])
class Solution {
    public int maximumSum(int[] a) {
        int n = a.length, INF = (int) -2e5, max = a[0], f[][] = new int[n][2];
        f[0][0] = a[0];
        f[0][1] = 0;
        
        for (int i = 1; i < n; i++) {
            f[i][0] = Math.max(a[i], f[i-1][0] + a[i]);
            f[i][1] = Math.max(f[i-1][0], f[i-1][1] + a[i]);
            max = Math.max(max, Math.max(f[i][0], f[i][1]));
        }
        return max;
    }
}

複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()

方法二:空間壓縮

可以進行空間壓縮,因爲 f[i][0] 和 f[i][1] 只與前前一個狀態有關

class Solution {
    public int maximumSum(int[] a) {
        int n = a.length, max = a[0];
        int fi_0 = a[0], fi_1 = 0;

        for (int i = 1; i < n; i++) {
            int pre_fi_0 = fi_0;
            fi_0 = Math.max(fi_0 + a[i], a[i]);
            fi_1 = Math.max(fi_1 + a[i], pre_fi_0);
            max = Math.max(max, Math.max(fi_0, fi_1));
        }
        return max;
    }
}

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(1)O(1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章