LeetCode 907: 子数组的最小值之和-单调栈的运用 |Sum of Subarray Minimums-Fantasy use of Monotonic Stack

Tags: #MonoStack #Stack

Problem Description

Given an array of integers arr, find the sum of min(b), where b ranges over every (contiguous) subarray of arr. Module the answer (10^9+7).

Example:

Input: arr = [3,1,2,4]
Output: 17
Explanation:
Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4].

Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1.

Sum is 17.

Problem Analysis & Transformation

We are asked to get each subarray’s min, and sum them up. The straightforward way is to calculate the minimum value of each subarray, and sum them up.

We can transform this question to another one. For each element i(i is the index), find the number of subarrays whose minimum element is that element, mark as #i.

In the above example:
#0=1, the range is [3], the subarray is [3].
#1=6, the range is [3,1,2,4], those subarrays are [3,1], [1], [1,2], [1,2,4], [3,1,2], [3,1,2,4].
#2=2, the range is [2,4], those subarrays are [2], [2,4].
#3=1, the range is [4], the subarray is [4].

So the total sum is each element’s value times the number of subarrays it corresponding to. totalSum=sum(arr[i]*#i).
totalSum=1*3+6*1+2*2+4*1=17

If there are two same elements, they will find same subarrays. We deal with this situation as follows:
Every element’s subarrays’ left edge is the first element that small or equal to it(if there is none, mark as -1), the right edge is the first element that strictly less than it(if non, mark as n: length of arr).

Here is an example:
arr = [3,1,5,1,2,4]
The subarray range of the right 1([3,1,5,_1_,2,4]) is [1,2,4]. The subarray range of the left 1([3,_1_,5,1,2,4]) is [3,1,5,1,2,4]. So that those two 1’s subarrays won’t be intersected.

So the method to find subarray range is:

Given an element e, find the first element less than or equal to e to the left as the left boundary, and the first element strictly less than e to the right as the right boundary. The range does not contain boundaries.

The proof maybe incomplete…
The proof is divided into two aspects:

If there is a subarray sArr that is not contained. Assume the minimum element of sArr is e. In the find subarray step, all subarray which has no element small than e should be found. That’s a contradiction. Even there are two same elements in sArr, at least one has contained this subarray.

Assume there is a subarray sArr which is found by two different element e and v(different in index, may same in value).

Case 1: e!=v
Since e=min(sArr) and v=min(sArr), so e=v, that’s a contradiction.

Case 2: e=v
As explained in above boundary situation, as index of e is not equal to v, w.o.l.g, assume index of e is smaller than index of v. So the range of e‘s subarray should be [..e..v...], while the range of v‘s subarray should be [..v...] which does contain element e and even left. So e and v won’t find a same subarray(because the subarray range is different).

In last part, we find the subarray range of an elements e, where each element in the subarray is equal or bigger than e.

So the problem comes: How to count the number of the subarrays of that range?

It’s quite easy. The left side elements number is idx(e)-leftBound, they can form idx(e)-leftBound subarrays(remember subarray must contain e). The right side elements number is rightBound-idx(e), they can form rightBound-idx(e) subarrays. The left and right sides are combined in pairs to produce all subarrays: #idx(e)=(idx(e)-leftBound)*(rightBound-idx(e)).

So the answer is totalSum=sum(arr[i]*#i).

Review of problem transformation process

To find next smaller value, use mono-stack!

Coding Details

We need to find the first element less than or equal to each element to the left, and the first element strictly less than each element to the right. Problem like this, finding the one-side small, should be solved using monotonic stack.

We can use an increasing stack, when pushing an element, popping until the peek element of the stack is smaller than or equal to the pushing element. Every popped element’s right side is also determined, just like Largest Rectangle in Histogram previous blog.

When popping an element, we know it’s left bound, the peek element of stack, we also know it’s right bound, the pushing element. So we add its contribution to the answer.

The answer maybe quite large, so we need to module (10^9+7) when calculating.

Since there may be no smaller element in left, so we set it to -1. Same as the right side, set it to n.

In the pushing process, we also push -1 and n to the stack, the value corresponding to it is infinitesimal. We pushing -1 first because every element are larger than it, so it can be proper boundary when popping. We pushing n finally because every element are also larger than it(except the first -1), so when pushing n, all elements of arr will be popped out, and their right boundary are n. That’s understandable, because when pushing n, there is only a monotonically increasing sequence left in the stack.

The code as follows:

public class Solution {
    int[] arr;
    int n;

    public int sumSubarrayMins(int[] arr) {
        int MOD = 1_000_000_007;

        // handle input arr's error
        if (arr == null || arr.length == 0) {
            return 0;
        }
        this.arr = arr;
        n = arr.length;

        long ans = 0L;
        Deque increStack = new ArrayDeque<>();
        // add index -1 and n into the process(their value are minInfinity) so that
        // don't need to consider boundary situation.

        for (int i = -1; i

Original: https://www.cnblogs.com/liuzhch1/p/16421111.html
Author: liuzhch1
Title: LeetCode 907: 子数组的最小值之和-单调栈的运用 |Sum of Subarray Minimums-Fantasy use of Monotonic Stack

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606694/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【设计模式】Java设计模式-外观模式

    Java设计模式 – 外观模式 😄 不断学习才是王道🔥 继续踏上学习之路,学之分享笔记👊 总有一天我也能像各位大佬一样🏆原创作品,更多关注我CSDN: 一个有梦有戏的人…

    Linux 2023年6月6日
    0158
  • 006 Linux 命令三剑客之-grep

    01 一起来认识 grep! Linux 命令三剑客,sed、grep、awk。 sed:擅长数据修改。 grep:擅长数据查找定位。 awk:擅长数据切片,数据格式化,功能最复杂…

    Linux 2023年5月27日
    0107
  • JDK 环境变量配置

    一、环境准备 Windows10 jdk-9.0.1 二、下载合适的JDK版本,安装JDK 三、环境变量配置 1、右键桌面上”我的电脑”>>&#…

    Linux 2023年6月8日
    091
  • redis 基于SpringBoot Reids 的工具类

    redis 基于SpringBoot Reids 的工具类 package com.mhy.springredis.utils; import org.springframewor…

    Linux 2023年6月7日
    0123
  • jarwarSpringBoot加载包内外资源的方式,告别FileNotFoundException吧

    工作中常常会用到文件加载,然后又经常忘记,印象不深,没有系统性研究过,从最初的war包项目到现在的springboot项目,从加载外部文件到加载自身jar包内文件,也发生了许多变化…

    Linux 2023年6月6日
    0115
  • springboot分析——与其他组件的整合(JPA规范/atomikos/redis)

    一:与JPA规范整合 jpa是一套orm的规范,提供api接口,hirebnate就是对jpa的一套实现,下面我们看看springboot如何 与jpa整合 1:添加依赖和配置 j…

    Linux 2023年5月28日
    0120
  • FusionAccess桌面云安装(windows AD方法)

    创建FusionAccess虚拟机 选择自定义 默认兼容 选择稍后安装操作系统 选择Linux SUSE Linux 名字位置自己选择 选择最少4个处理器 选择最少8G内存 选择仅…

    Linux 2023年6月8日
    0110
  • 2021年3月-第03阶段-前端基础-JavaScript基础语法-JavaScript基础第01天

    1 – 编程语言 1.1 编程 编程: &#x5C31;&#x662F;&#x8BA9;&#x8BA1;&#x7B97;&amp…

    Linux 2023年6月8日
    0101
  • USB_ModeSwitch for Android 7

    测试步骤: 2.运行命令 adb shell usbmodeswitch -W -v 12d1 -p 1f01 -M ‘555342431234567800000000…

    Linux 2023年6月7日
    081
  • 笔记:linux 总结

    1.开始 Linux,全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统,其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布,它主要受到Minix和…

    Linux 2023年6月14日
    0108
  • csrf跨站请求伪造;auth模块

    csrf跨站请求伪造 针对csrf相关的校验有很多种方式,django只是提供了一些而已 form表单 前提必须是前后端整合,能够使用模板语法 {% csrf_token %} 当…

    Linux 2023年6月7日
    093
  • [20220302]oracle如何定位使用library cache mutex 2.txt

    [20220302]oracle如何定位使用library cache mutex 2.txt –//这个问题实际上困扰我很久,我开始以为library cache b…

    Linux 2023年6月13日
    087
  • QT官方社区及版本说明

    Qt版本说明 版本分类 Qt商业版:提供给商业软件开发。它们提供传统商业软件发行版并且提供在协议有效期内的免费升级和技术支持服务。 Qt开源版:提供了和商业版本同样的功能。它是免费…

    Linux 2023年6月13日
    0174
  • 小公司比较吃亏的两道微服务面试题

    其实选择工作的时候,很多技术牛人都会选择一些小而美的公司,技术全面,能够以一个更全面的视角看整个公司的运作,人和人之间的相处也很简单。但是,有两道微服务的面试题,小公司的朋友们会比…

    Linux 2023年6月14日
    0109
  • Nginx笔记

    实现负载均衡 这里采用的是权重 进入配置文件目录cd /usr/local/nginx/conf/ //实际根据自己的目录来 编辑vim nginx.conf 根据需要在此代码的顶…

    Linux 2023年5月27日
    0105
  • 【Python】**kwargs和takes 1 positional argument but 2 were given

    Python的函数定义中可以在参数里添加kwargs——简单来说目的是允许 添加不定参数名称的参数,并作为 字典传递参数。但前提是——你必须提供 参数名**。 例如下述情况: 1 …

    Linux 2023年6月13日
    0114
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球