84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

输入:heights = [2,1,5,6,2,3] 输出:10 解释:最大的矩形为图中红色区域,面积为 10 示例 2:

输入: heights = [2,4] 输出: 4

提示:

1 <= heights.length <=10^5 0 <= heights[i] <= 10^4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
    public int largestRectangleArea(int[] heights) {
        int n=heights.length;
        int []ph=new int [n+2];
        int ans=0;
        for(int i=1;i<n+1;i++) ph[i]=heights[i-1];
        Deque<Integer> stack=new ArrayDeque<>();
        for(int i=0;i<n+2;i++){
          //  System.out.println(i+" "+stack);
            while(!stack.isEmpty()&&ph[stack.getLast()]>ph[i]){
               
                int cur=stack.removeLast();
                ans=Math.max(ans,(i-stack.getLast()-1)*ph[cur]);
            }
            stack.offer(i);
        }
        return ans;
    }
}

这一题是干嘛呢?找到i左边和右边小于它的第一个数,中间就是最大面积了。

方法是单调栈。

注意栈里面记录的是下标。

在Java中使用的是ArrayDeque数据结构。

所以我建议看到有类似最右最左边找最小的数,优先来看看84是如何实现单调栈的。

我们每次弹出的时候做计算!!

为了加深印象,遂添加cpp题解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n=heights.size();
        vector<int> v(n+2);
        for(int i=0;i<n;i++){
            v[i+1]=heights[i];
        }
        stack<int> s;
        int ans=0;
        for(int i=0;i<n+2;i++){
            while(!s.empty()&&v[s.top()]>v[i]){
                int cur=s.top();
                s.pop();
                ans=max(ans,v[cur]*(i-s.top()-1));

            }
            s.push(i);
            
        }
        return ans;

    }
};

907. 子数组的最小值之和

难度中等402

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。

由于答案可能很大,因此 返回答案模 10^9 + 7

示例 1:

1
2
3
4
5
输入:arr = [3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。 
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。

示例 2:

1
2
输入:arr = [11,81,94,43,3]
输出:444

提示:

  • 1 <= arr.length <= 3 * 104
  • 1 <= arr[i] <= 3 * 104

通过次数20,094

提交次数58,149

注意也是在弹出栈的时候做计算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
    int sumSubarrayMins(vector<int>& arr) {
        int n=arr.size();
        vector<int> v(n+2);
        for(int i=0;i<n;i++){
            v[i+1]=arr[i];
        }
        stack<int> s;
        int MOD=1000000007;
        long ans=0;
        for(int i=0;i<n+2;i++){
            while(!s.empty()&&v[s.top()]>v[i]){
                int cur=s.top();
                s.pop();
               // printf("left:%d,mid=%d right%d,\n",s.top(),(cur),(i));
                ans+=1l*(i-cur)%MOD*(cur-s.top())%MOD*v[cur];
                ans%=MOD;
            }
            s.push(i);
        }
        return (int)ans%MOD;
    }
};