删除一次得到子数组最大和
题目来源 LeetCode link
一、题目
Description
给你一个整数数组,返回它的某个 非空 子数组(连续元素)在执行一次可选的删除操作后,所能得到的最大元素总和。
也就是说,从一个数组中找出一个连续的子数组,你可以从这个子数组中选择是否删除一个元素,得到最大的子数组和。
注意
可以选择删除一个元素,也可以不删除。
删除一个元素后,子数组不能为空。
Input
输入的第一行是用例个数T,第二行是数组长度n,第三行是数组,数组元素用空格分割。
Output
输出最大子数组的和。
提示:
1 <= arr.length <= 10^5
-10^4 <= arr[i] <= 10^4
Sample Input 1
2
4
1 -2 0 3
4
-2 -1 -3 -4
Sample Output 1
4
-1
二、解题思路
使用动态规划思想。
-
构建二维数组 dp[2][n]
本题要求最多删除一个元素,则该数组构建为2行,n列。
第0行 dp[0][j] 表示前j个元素中不删除的最大子数组的和;
第1行 dp[1][j] 表示前j个元素中删除一个的最大子数组的和;
-
dp[i][j] 初始化
dp[0][0] = arr[0];
-
初始化第0行 (前j个元素不删除的最大子数组和)
dp[0][j] = Math.max(0, dp[0][j - 1]) + arr[j]; //j从1开始
dp[0][j] 有两种情况:
① 前j-1个元素的和小于0时,加上arr[j], 就小于arr[j],此时就以arr[j]开始重新累加,即dp[0][j]=0+arr[j];
② 前j-1个元素的和大于0时,就把arr[j]加上,即dp[0][j]=dp[0][j-1]+arr[j];
取以上两者中的最大值。
-
初始化第1行 (前j个元素删除一个元素的最大子数组和)
dp[1][j] = Math.max(dp[1][j - 1] + arr[j], dp[0][j - 1]); //j从1开始
对于第j个元素,有两种情况:
① 从前j-1个元素中删除一个,在加上arr[j],也就是前j个元素删除一个了一个,即dp[1][j]=dp[1][j-1]+arr[j];
② 删除第j个元素,值为前j-1个元素不删除的最大子数组和,即dp[1][j]=dp[0][j-1];
从以上两者中选最大值。
注意:dp[1][0]不考虑,默认为0就可以,因为子数组不能为空。
如
dp[1][1] = Math.max(dp[1][0] + arr[1], dp[0][0]);
就是在arr[0]到arr[1]中删除一个的最大值;
-
三、代码
java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int numOfTestcase = scanner.nextInt();
while (numOfTestcase-- > 0) {
int n = scanner.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
System.out.println(maximumSum(arr));
}
}
public static int maximumSum(int[] arr) {
int n = arr.length;
//数组有2行,第0行为不删除元素的最大子数组和,第1行为删除一个元素的最大子数组和
//dp[1][3]为前4个元素中删除一个元素的最大子数组和
int[][] dp = new int[2][n];
//初始化
int max = arr[0]; //max为不删除和删除一个元素的子数组和中的最大值
//初始化 dp[0][0],子数组不能为空,最少为一个
dp[0][0] = arr[0];
for (int j = 1; j < n; j++) {
//dp[0][j] 不删除元素的最大子数组和
dp[0][j] = Math.max(0, dp[0][j - 1]) + arr[j];
max = Math.max(max, dp[0][j]);
//dp[0][j] 删除一个元素的最大子数组和
dp[1][j] = Math.max(dp[1][j - 1] + arr[j], dp[0][j - 1]);
max = Math.max(max, dp[1][j]);
}
return max;
}
}