代码随想录算法训练营第六十三天| 84.柱状图中最大的矩形

题目与题解

 84.柱状图中最大的矩形

题目链接: 84.柱状图中最大的矩形

代码随想录题解: 84.柱状图中最大的矩形

视频讲解:单调栈,又一次经典来袭! LeetCode:84.柱状图中最大的矩形_哔哩哔哩_bilibili

解题思路:

        看答案,不为难自己

看完代码随想录之后的想法 

        重点还是怎么将应用题翻译成数学题,才能选择合适的做法。

        要求最大的矩形,其实就是以某一个最低高度为矩形的高,将其周围不小于它的高度的柱子宽度加在一起,作为矩形的宽。这样翻译过来,就是要求每一个高度左边和右边第一个高度小于它的下标,这样,左右下标之间的柱子就是矩形的宽度。

        与接雨水的题稍微有点反过来,略复杂了一些。

        1. 双指针法

        遍历两遍heights,分别计算其每个下标左边第一个高度小于它的下标minLeftIndex和每个下标右边第一个高度小于它的下标minRightIndex。为了提高计算效率,以计算左边下标为例,不需要逐一遍历其左边的所有数字中直到找到第一个下标,如果其左边某一个下标高度高于它,那直接取t = minLeftIndex[t]为当前最小下标即可,直到t < 0。为了防止死循环,minLeftIndex[0]初始化要赋值为-1。右边同理。

        求完这两个数组后,遍历0-size-1,求出每一个下标对应的最大矩阵大小为minRightIndex[i] - minLeftIndex[i]-1)*heights[i],最后取最大值即可。

class Solution {
    public int largestRectangleArea(int[] heights) {
		// 双指针
		int size = heights.length;
		int[] minLeftIndex = new int[size];
		minLeftIndex[0] = -1;
		for (int i = 1; i < size; i++) {
			int t = i-1;
			while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
			minLeftIndex[i] = t;
		}
		int[] minRightIndex = new int[size];
		minRightIndex[size-1] = size;
		for (int i = size - 2; i >= 0; i--) {
			int t = i+1;
			while (t < size && heights[t] >= heights[i]) t = minRightIndex[t];
			minRightIndex[i] = t;
		}
		int res = heights[0];
		for (int i = 0; i < size; i++) {
			res = Math.max(res, (minRightIndex[i] - minLeftIndex[i]-1)*heights[i]);
		}
		return res;
    }
}

2. 单调栈

        这次的单调栈要变成栈底到栈顶从小到大排列的顺序了,因为要求的是更高的高度对应矩阵的面积。

        这样跟接雨水也很类似,如果当前height[i]大于height[s.peek()]直接入栈,如果相等就弹出一个再入栈一个,否则当栈不为空且height[i]小于height[s.peek()]时,循环计算当前矩形的高度mid = height[s.peek()]并弹出栈顶,如果此时栈不为空,就可以获得其左边第一个比它小的高度的下标s.peek()和右边第一个比它小的高度i,得到矩形宽为 i - s.peek() - 1,求得其面积。最后比较得到最大面积即可。

        这里需要注意,heights不能直接使用,要先在其前后加两个值0,生成新的矩阵。否则当当前数组是单调的时候,是无法进入计算其面积的循环里面的。

class Solution {
    public int largestRectangleArea(int[] heights) {
		// 单调栈
		Stack<Integer> s = new Stack<>();
		int[] newHeight = new int[heights.length+2];
		System.arraycopy(heights, 0, newHeight, 1, heights.length);
		s.push(0);
		int res = 0;
		for (int i = 1; i < newHeight.length; i++) {
			if (newHeight[i] > newHeight[s.peek()]) {
				s.push(i);
			} else if (newHeight[i] == newHeight[s.peek()]){
				s.pop();
				s.push(i);
			} else {
				while (!s.isEmpty() && newHeight[i] < newHeight[s.peek()]) {
					int mid = s.pop();
					if (!s.isEmpty()) {
						int w = i - s.peek() - 1;
						res = Math.max(res, w * newHeight[mid]);
					}
				}
				s.push(i);
			}
		}
		return res;
    }
}

遇到的困难

        应用题还是得知道怎么翻译。

        单调栈的细节也很多,容易写错。

今日收获

        最后一题单调栈,还是有点云里雾里,得再练。

        收工了!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值