博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LeetCode 152. Maximum Product Subarray 解题报告
阅读量:2360 次
发布时间:2019-05-10

本文共 2724 字,大约阅读时间需要 9 分钟。

LeetCode 152. Maximum Product Subarray 解题报告

题目描述

Find the contiguous subarray within an array (containing at least one number) which has the largest product.


示例

Example 1:

given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.


注意事项

没有给出.


解题思路

我的思路1:

这道题跟以前做的一道求最大连续子序列和的问题类似,不同的是这道题求的是最大积。很自然能够想到用动态规划去解,设置一个数组dp,dp[i]表示以nums[i]结尾的子序列的最大积,初始状态:

dp[0] = nums[0];
状态转移方程就是:
dp[i] = max(dp[i - 1] * nums[i], nums[i])
这样就OK啦!
好吧,开玩笑的,如果真的是这样做,就完全掉入了这道题的陷阱里。求积里有个很重要的性质:负负得正。因此,如果有仔细观察题目的例子,会发现序列中会有负数的!所以,仅是记录最大值是不够的,比如序列[2, -1, -3],正确答案是 1×3=3 ,然而用上面那个解法会得到2,原因就在于中间计算时可能会产生负值,但我们不能判断当前的负值会不会与后面的负值相乘得到更大的结果。

正确的解法应该是同时记录最大积和最小积,dp[i][0]表示以nums[i]结尾的子序列的最小积,dp[i][1]表示以nums[i]结尾的子序列的最大积。

初始状态:
dp[0][0] = nums[0];
dp[0][1] = nums[0];
由于可能存在负数,所以有三个数参与判断,状态转移方程:
dp[i][0] = min( min(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i]), nums[i])
dp[i][1] = max( max(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i]), nums[i])
可以在用一个变量result记录结果,每次计算出最大积时就更新一下result,最后返回result就行,见下面我的代码1,时间复杂度是 O(n) ,空间复杂度是 O(n)

优化思路:

通过状态转移方程可以看出计算dp[i][]时只需要用到dp[i - 1][],与dp[i - 2][]及前面的结果没有关系,因此空间复杂度可以进一步优化,只用两个变量minPro和maxPro存储前一个位置的最大积和最小积。

初始状态:
minPro = nums[0];
maxPro = nums[0];
状态转移方程:
minPro = min( min(minPro * nums[i], maxPro * nums[i]), nums[i])
maxPro = max( max(minPro * nums[i], maxPro * nums[i]), nums[i])
另外状态转移方程中重复做了两次乘法,所以可以用变量先算出结果再进行判断,见下文中我的代码2,时间复杂度是 O(n) ,空间复杂度是 O(1)


代码

我的代码1:

class Solution {public:    int maxProduct(vector
& nums) { int n = nums.size(), result = nums[0]; // dp[i][0] min, dp[i][1] max vector
> dp(n, vector
(2, nums[0])); dp[0][0] = nums[0]; dp[0][1] = nums[0]; for (int i = 1; i < n; i++) { dp[i][0] = min(min(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i]), nums[i]); dp[i][1] = max(max(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i]), nums[i]); if (dp[i][1] > result) { result = dp[i][1]; } } return result; }};

我的代码2:

class Solution {public:    int maxProduct(vector
& nums) { int n = nums.size(), result = nums[0]; int minPro = nums[0], maxPro = nums[0]; int temp0 = 0, temp1 = 0; for (int i = 1; i < n; i++) { temp0 = minPro * nums[i]; temp1 = maxPro * nums[i]; minPro = min(min(temp0, temp1), nums[i]); maxPro = max(max(temp0, temp1), nums[i]); result = max(maxPro, result); } return result; }};

总结

这道题是一道比较经典的子序列变种体,关键是弄清楚结果的产生情况,既可能是由正数相乘得到,也有可能是由负数得到,所以必须存储最大积和最小积。

动归的题目通过之后可以想想能不能优化,一般是针对空间进行优化。因为我的能力比较差,所以一开始都是开最大的空间((⊙﹏⊙)b)。通过想想优化,能够更好地体会状态转移的过程,所以得养成这个习惯,勤能补拙,继续加油啦~

转载地址:http://pqntb.baihongyu.com/

你可能感兴趣的文章
android.os.NetworkOnMainThreadException
查看>>
Android:单元测试Junit的配置
查看>>
国际产业
查看>>
制造业
查看>>
混沌的有关概念——1
查看>>
混沌的有关概念——2
查看>>
混沌理论的简要观点
查看>>
知识的经济学分析:一个文献综述——基于范式演进的视点
查看>>
reading the path of picture
查看>>
Could a 32bit software install on a 64bit-system computer
查看>>
No reship system to recovery disk AHCI diriven and just do it
查看>>
debug compare with release
查看>>
QT5.7 deploys opencv2.4.13(the version of opencv is not newer than QT)
查看>>
the principle of laplacian filter
查看>>
WinCE动态修改启动LOGO
查看>>
WINCE 的内存管理
查看>>
Windows Mobile 编译的内部结构和步骤
查看>>
WinCE BSP中的Dirs文件和Sources文件
查看>>
CE下基于Zylonite硬件平台的SD卡驱动开发
查看>>
GPRS管理与创建APN拨号连接
查看>>