前缀和+单调栈:5752、子数组最小乘积的最大值

思路: 理解一个概念,当最小值确定后,连续子数组要尽可能地长,得到的是指定连续数组最小值后最小乘积的最大值。首先求出数组的前缀和数组,用于计算任意两个索引之间元素的和,然后假设数组中的每一个元素都可以作为连续子数组中的最小值,维护left和right两个数组,分别存放左边比当前元素值小的第一个元素索引,右边比当前元素值小的第一个元素索引,该过程使用单调栈求解,最后以原数组中每个元素为最小值,通过left数组和right数组求得连续数组的最小乘积,取结果最大的即可。

class Solution {
    public int maxSumMinProduct(int[] nums) {
        int n=nums.length;
        long[] presum=new long[n+1];
        presum[0]=0;
        //前缀和数组
        for(int i=1;i<=n;i++){
            presum[i]=presum[i-1]+nums[i-1];
        }
        //使用单调栈求左、右第一个小于当前元素值的元素的索引。
        Deque<Integer> stack1=new LinkedList<>();
        Deque<Integer> stack2=new LinkedList<>();
        int[] left=new int[n];
        int[] right=new int[n];
        for(int i=0;i<n;i++){
            //弹出左边所有大于当前元素值的元素索引
            while(!stack1.isEmpty()&&nums[i]<=nums[stack1.peek()]){
                stack1.pop();
            }
            //栈为空,说明当前元素是所有左边元素的最小值,连续子数组的左边界设为-1
            if(stack1.isEmpty()){
                left[i]=-1;
            }else{
                //栈不为空,连续子数组的左边界为栈顶元素,即第一个比当前元素值小的元素的索引
                left[i]=stack1.peek();
            }
            //当前元素的索引进栈
            stack1.push(i);
        }
        //同上,找比当前元素值小的第一个右边元素
        for(int i=n-1;i>=0;i--){
            while(!stack2.isEmpty()&&nums[i]<=nums[stack2.peek()]){
                stack2.pop();
            }
            if(stack2.isEmpty()){
                right[i]=n;
            }else{
                right[i]=stack2.peek();
            }
            stack2.push(i);
        }
        long res=0;
        for(int i=0;i<n;i++){
            //以当前元素为最小值的连续子数组的最小乘积
            long sum=nums[i]*(presum[right[i]]-presum[left[i]==-1?0:left[i]+1]);
            res=Math.max(res,sum);
        }
        return (int)(res%1000000007);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值