leetcode【152】【tag array】Maximum Product Subarray【c++版本,多种写法】

解决LeetCode 152题,寻找整数数组中连续子数组的最大乘积。讨论了动态规划的二维和一维解法,并分享了一种更高效的策略,避免了无脑比较,降低了时间复杂度。
摘要由CSDN通过智能技术生成

问题描述:

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Example 1:

Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.

Example 2:

Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.

源码:

受到大佬的启发,从今天开始按照tag刷题。

看到这个题目第一个想法当然就是动态规划。就想到了用一个二维数组dp[i][j]表示第i个元素到第j个资数组的乘积,然后求出最大值,最后结果,超时。最后一个用例没通过。

超时代码

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)  return 0;
        vector<vector<int>> dp(n+1, vector<int>(n+1, 1));
        // int flag = 0;   // 记录最小的元素
        int result = INT_MIN;
        for(int j=1; j<=n; j++){
            for(int i=1; i<=j; i++){
                if(j-1>=i)  dp[i][j] = dp[i][j-1] * nums[j-1];
                else    dp[i][j] = nums[j-1];
                // cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
                result = max(result, dp[i][j]);
            }
        }
        return result;
    }
};

然后我就想着用一维的动态规划,小编实力太差了,弄了半天也调了,写了一个思路出来。时间和空间都只有可怜的5%。

用dp[i]表示以i结尾的子集的最大乘积大小。index[i]表示该子集的开头的位置,

当nums[i-1]和dp[i-1]都大于0的时候,说明可以直接衔接上,直接相乘;

当nums[i-1]和dp[i-1]都小于0的时候,说明可以直接衔接上,直接相乘,但是此时万一dp[index[i-1]]>=0,也就是dp[i-1]所选定的子集的前一个元素大于0,此时也应该乘上;

当nums[i-1]小于0和dp[i-1]大于0的时候,此时需要考虑dp[i-1]的子集的前一个元素是否小于,若是小于0,则可以直接连接两个子集;

当nums[i-1]小于0和dp[i-1]大于0的其他时候,则需要遍历了;

其他情况,直接等于本身nums[i-1]。

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)  return 0;
        vector<int> dp(n+1, 1);
        vector<int> index(n+1, 0);
        int result = INT_MIN;
        for(int i=1; i<=n; i++){
            if(dp[i-1]>0 && nums[i-1]>0){
                dp[i] = dp[i-1]*nums[i-1];
                index[i] = index[i-1];
            }
            else if(dp[i-1]<0 && nums[i-1]<0){
                dp[i] = dp[i-1]*nums[i-1];
                index[i] = index[i-1];
                if(index[i-1]>=0 && dp[index[i-1]]>0){
                    dp[i] *= dp[index[i-1]];
                    index[i] = index[index[i-1]];
                }
            }
            else if(nums[i-1]<0 && dp[i-1]>0 && index[i-1]-1>=0 && nums[index[i-1]-1]<0){
                dp[i] = dp[i-1] * nums[i-1] * nums[index[i-1]-1];
                index[i] = index[i-1]-1;
                if(dp[index[i-1]-1]>0){
                    dp[i] *= dp[index[i-1]-1];
                    index[i] = index[index[i-1]-1];
                }
            }
            else if(nums[i-1]<0 && dp[i-1]>0){
                int tmp = dp[i-1], j=0, flag=0;
                for(j=index[i-1]; j<i-1; j++){
                    cout<<nums[j]<<endl;
                    tmp = tmp/nums[j];
                    if(nums[j]<0){
                        flag = 1;
                        break;
                    }
                }
                if(flag){
                    dp[i] = tmp*nums[i-1];
                    index[i] = j+1;   
                }
                else{
                    dp[i] = nums[i-1];
                    index[i] = i-1;
                }
            }
            else{
                dp[i] = nums[i-1];
                index[i] = i-1;
            }
            cout<<dp[i]<<" "<<index[i]<<endl;
            result = max(result, dp[i]);
        }
        return result;
    }
};

然而,翻了一下discuss区,这可能就是本垃圾和大佬的差距吧:

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

为了防止无脑比较,可以采用分类的方式(不过比小编自己的那个简单得多)。

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值