152. 乘积最大子数组
给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
子数组 是数组的连续子序列。
示例 1:
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
提示:
- 1 <= nums.length <= 2 ∗ 1 0 4 2 * 10^4 2∗104
- -10 <= nums[i] <= 10
- nums 的任何前缀或后缀的乘积都 保证 是一个 32-位 整数
解法
- 动态规划:四个步骤:
- 问题定义
- 状态转移方程
- 初始条件和边界情况
- 确定计算顺序(自顶向下,还是自下向上)
问题定义:
连续乘积的最大子数组,如果借鉴最大子数组和的思路做是有问题,因为乘积涉及到正负问题,负负得正。两个大的负数相乘得到的值可能大于当前的正数。因此这里需要保留每个状态下的最大值和最小值。min_dp[i]表示以i结尾的时候的最小连续乘积,max_dp[i]表示以i结尾的时候的最大连续乘积;
状态转移方程:
min_dp[i] = min(min_dp[i-1] * nums[i], max_dp[i-1] * nums[i], nums[i])
max_dp[i] = max(min\_dp[i-1] * nums[i], max_dp[i-1] * nums[i], nums[i])
初始化条件和边界条件
min_dp[0] = nums[0]
max_dp[0] = nums[0]
确定计算顺序:
这个是从下向上的方向计算即可
代码实现
动态规划
python实现
class Solution:
def maxProduct(self, nums: List[int]) -> int:
n = len(nums)
if n == 1:
return nums[0]
min_dp = [0] * n
max_dp = [0] * n
min_dp[0] = nums[0]
max_dp[0] = nums[0]
for i in range(1, n):
min_dp[i] = min(min_dp[i-1]*nums[i], max_dp[i-1]*nums[i], nums[i])
max_dp[i] = max(min_dp[i-1]*nums[i], max_dp[i-1]*nums[i], nums[i])
return max(max_dp)
c++实现
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
if (n == 1) return nums[0];
vector<int> min_dp (n, 0);
min_dp[0] = nums[0];
vector<int> max_dp (n, 0);
max_dp[0] = nums[0];
for (int i=1; i<n; i++) {
min_dp[i] = min(min_dp[i-1] * nums[i], min(max_dp[i-1] * nums[i], nums[i]));
max_dp[i] = max(min_dp[i-1] * nums[i], max(max_dp[i-1] * nums[i], nums[i]));
}
return *max_element(max_dp.begin(), max_dp.end());
}
};
复杂度分析
- 时间复杂度: O ( N ) O(N) O(N)
- 空间复杂度: O ( N ) O(N) O(N)
动态规划优化成两个值
由于状态的改变只与前一个元素的最小值和最大值有关,我们只需要保存最近的元素状态的最大值和最小值即可,以及一个最大值
python实现
class Solution:
def maxProduct(self, nums: List[int]) -> int:
n = len(nums)
if n == 1:
return nums[0]
max_dp = nums[0]
min_dp = nums[0]
ans = nums[0]
for i in range(1, n):
mx = max_dp
mn = min_dp
max_dp = max(mx * nums[i], mn * nums[i], nums[i])
min_dp = min(mx * nums[i], mn * nums[i], nums[i])
ans = max(ans, max_dp)
return ans
c++实现
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
if (n == 1) return nums[0];
int max_dp = nums[0], min_dp = nums[0], ans = nums[0];
for (int i=1; i<n; i++) {
int mx = max_dp, mn = min_dp;
max_dp = max(mx * nums[i], max(mn * nums[i], nums[i]));
min_dp = min(mx * nums[i], min(mn * nums[i], nums[i]));
ans = max(ans, max_dp);
}
return ans;
}
};
注意参数更新,需要中间变量。否则前一个的更新会导致后一个值的更新不对,不是前一个状态的值。
复杂度分析
- 时间复杂度: O ( N ) O(N) O(N)
- 空间复杂度: O ( 1 ) O(1) O(1)
参考
原文地址:https://www.jb51.cc/wenti/3287024.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。