leetcode [152. 乘积最大子数组]

(https://leetcode-cn.com/problems/maximum-product-subarray/)

直接暴力会超时,如果超时,要么这题需要用数据结构进行优化,要么就是用的算法有问题。这题想了一会不知道能用什么数据结构进行优化,于是就看了眼题目标签,发现上面有写动态规划。刚开始我的dp过程想错了,因为按照我的常规,想动态规划就是直接跳到最后一步,假设所给的数组为nums[x],我就在想如果已经给我了nums[x-1]的乘积最长的子数组,怎么与nums[x]扯上关系......想不出来瞄了一眼答案,发现我的过程想错了(可能是因为睡眠不足的原因

这类求解子数组的题目如果涉及到了dp,那么dp[i]就表示以第i个元素结尾的符合题目要求的答案,就是加上个强制性条件可以使过程更加简单。这题dp[i]就表示以第i个元素结尾的数组中最大连续子数组的乘积,这样dp过程就变得很简单了,因为dp[i] 表示一定选了第i个,所以我们就可以很容易的写出状态转移式,但这时感觉还是不太对,数组中元素有负数,负数是可以把最大值变成最小值,把最小值变成最大值的,所以某一项的最大值dp可能的来源有两个,所以我们对dp再加一维,dp[i] [0]表示以第i项结尾中子数组的最大值,dp[i] [1] 表示以第i项结尾中子数组的最小值

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        vector<vector<int>> dp(n,vector<int>(2,0));
        dp[0][0] = dp[0][1] = nums[0];
        for(int i = 1; i < n; i++){
            if(nums[i] >= 0){
                dp[i][0] = dp[i-1][0]*nums[i];
                dp[i][1] = dp[i-1][1]*nums[i];
            }
            else {
                dp[i][0] = dp[i-1][1]*nums[i];
                dp[i][1] = dp[i-1][0]*nums[i];
            }
            dp[i][0] = max(dp[i][0],nums[i]); //如果dp[i-1][0]为负数,nums[i]为正数,那就不如直接从nums[i]重新开始了
            dp[i][1] = min(dp[i][1],nums[i]);
        }
        int ans = dp[0][0];
        for(int i = 1; i < n; i++) {
            //cout<<dp[i][0]<<"/"<<dp[i][1]<<" ";
            ans = max(ans,dp[i][0]);
        }
        return ans;
    }
};

总结:动态规划的思考过程不仅仅是直接跳到最后一步那一种方法,有时也要想想是不是需要对状态表示加一些强制条件

猜你喜欢

转载自www.cnblogs.com/Beic233/p/12911519.html