【題目】*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;
}
}