经过一次操作后的最大子数组和
难度:
标签:
题目描述
代码结果
运行时间: 168 ms, 内存: 27.0 MB
/*
* Leetcode 1746: Maximum Subarray Sum After One Operation
*
* 思路:
* 1. 使用流和并行流结合进行数组遍历。
* 2. 由于涉及到状态转移,不建议在流操作中使用副作用,采用传统for循环实现。
*/
import java.util.stream.IntStream;
public class Solution {
public int maxSumAfterOperation(int[] nums) {
int n = nums.length;
int[] dp1 = new int[n];
int[] dp2 = new int[n];
dp1[0] = nums[0];
dp2[0] = nums[0] * nums[0];
int maxSum = Math.max(dp1[0], dp2[0]);
IntStream.range(1, n).forEach(i -> {
dp1[i] = Math.max(dp1[i - 1] + nums[i], nums[i]);
dp2[i] = Math.max(dp1[i - 1] + nums[i] * nums[i], Math.max(nums[i] * nums[i], dp2[i - 1] + nums[i]));
maxSum = Math.max(maxSum, Math.max(dp1[i], dp2[i]));
});
return maxSum;
}
}
解释
方法:
该题解采用了动态规划的方法来求解最大子数组和的问题,在此基础上加入了一次平方操作的变体。具体地,使用两个状态变量 dp0 和 dp1 分别代表不使用平方操作和使用一次平方操作的最大子数组和的情况:
1. dp0 表示当前位置 i 不使用平方操作的最大子数组和,其状态转移方程为 dp0 = max(dp0 + x, 0),即考虑当前元素加入前一个子数组或者从当前元素开始新的子数组。
2. dp1 表示当前位置 i 使用了一次平方操作的最大子数组和,其状态转移方程为 dp1 = max(dp1 + x, dp0 + x * x),即考虑当前元素加入前一个已经使用了平方操作的子数组,或者在当前元素使用平方操作并加入之前没有使用平方操作的子数组。
循环遍历数组中的每一个元素,更新这两个状态,并实时维护一个全局最大值 maxVal,最终返回 maxVal。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
题解中提到的状态变量`dp0`和`dp1`具体是如何初始化的,为何选择这些初始值?
▷🦆
在算法中`dp1 = max(dp1 + x, dp0 + x * x)`的状态转移公式中,为什么同时考虑了`dp1 + x`和`dp0 + x * x`这两种情形?
▷🦆
算法在更新`dp0`和`dp1`时,为何使用`max(dp0 + x, 0)`而不是简单的`dp0 + x`,这样的设计有什么好处?
▷🦆
在遍历数组元素时,为什么要实时维护一个全局最大值`maxVal`,而不是在遍历完成后从`dp0`或`dp1`中选择一个最大值?
▷