53. 最大子数组和
dp[i]:用到了nums[i]连续子数组的最大和
用到了nums[i]连续子数组的最大和dp[i],要么是前面用到了nums[i - 1]的连续子数组最大和dp[i - 1],要么就是nums[i]
class Solution {
public:
// dp[i]:用到了nums[i]连续子数组的最大和
int maxSubArray(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 0);
dp[0] = nums[0];
int ans = nums[0];
for(int i = 1; i < n; i++){
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
ans = max(ans, dp[i]);
}
return ans;
}
};
152. 乘积最大子数组
数组的动态规划问题、连续子序列的一个常见的状态定义是:以下标 i 结尾的连续子序列的乘积的最大值
最后把整个 dp 数组看一遍求最大值即可。因此状态转移方程可能是:dp[i] = max(dp[i - 1] * nums[i], nums[i])
说明:牢记状态的定义,一定以下标 i 结尾,即:乘积数组中 nums[i] 必须被选取
针对这道题,dp状态有两维,第二维的状态有两个:
- dp[i][0]:用 0 表示遍历的过程中得到的以 nums[i] 结尾的连续子序列的乘积的最小值
- dp[i][1]:用 1 表示遍历的过程中得到的以 nums[i] 结尾的连续子序列的乘积的最大值
-
nums[i] >= 0
- 以nums[i]结尾的连续子序列的最大值dp[i][1],要么是前面序列最大乘积dp[i-1][1]用到了nums[i]的乘积,要么是放弃前面的序列dp[i-1][1],最大乘积就是nums[i]
- 以nums[i]结尾的连续子序列的最小值dp[i][0],要么是前面序列最小乘积dp[i-1][0]用到了nums[i]的乘积,要么是放弃前面的序列dp[i-1][0],最小乘积就是nums[i]
-
nums[i] < 0
- 以nums[i]结尾的连续子序列的最大值dp[i][1],要么是前面序列最小乘积dp[i-1][0]用到了nums[i]的乘积,要么是放弃前面的序列dp[i-1][0],最大乘积就是nums[i]
- 以nums[i]结尾的连续子序列的最小值dp[i][0],要么是前面序列最大乘积dp[i-1][1]用到了nums[i]的乘积,要么是放弃前面的序列dp[i-1][1],最小乘积就是nums[i]
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
// dp[i][0]:用到nums[i]的最小乘积
// dp[i][1]:用到nums[i]的最大乘积
vector<vector<int>> dp(n, vector<int>(2, 0));
dp[0][0] = nums[0];
dp[0][1] = nums[0];
int ans = dp[0][1];
for(int i = 1; i < n; i++){
if(nums[i] >= 0){
dp[i][1] = max(nums[i], dp[i - 1][1] * nums[i]);
dp[i][0] = min(nums[i], dp[i - 1][0] * nums[i]);
}else{
dp[i][1] = max(nums[i], dp[i - 1][0] * nums[i]);
dp[i][0] = min(nums[i], dp[i - 1][1] * nums[i]);
}
ans = max(ans, dp[i][1]);
}
return ans;
}
};
思路: 求最大值,可以看成求被0拆分的各个子数组的最大值
当一个数组中没有0存在,则分为两种情况:
-
负数为偶数个,则整个数组的各个值相乘为最大值;
-
负数为奇数个,则从左边开始,乘到最后一个负数停止有一个“最大值”,从右边也有一个“最大值”,比较,得出最大值
正反向各遍历一次,当前数nums[i]为0时,则把当前乘积mul重新置为1,ans记录遍历过程中最大的mul
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
int mul = 1;
int ans = nums[0];
for(int i = 0; i < n; i++){
mul *= nums[i]; // 记录[0,i]区间内的乘积
if(mul > ans) ans = mul;
if(nums[i] == 0) mul = 1; // 若当前值为0,则mul重新置为1
}
mul = 1;
for(int i = n - 1; i >= 0; i--){
mul *= nums[i];
if(mul > ans) ans = mul;
if(nums[i] == 0) mul = 1;
}
return ans;
}
};