2019.6.11 #程序员笔试必备# LeetCode 从零单刷个人笔记整理(持续更新)
这道hard智力题和之前刷过的炒股有点像。要想找到最大矩形面积,首先需要观察什么情况下能够构成一个局部最大的矩形。
对于高为h的矩形来说,其左边界left的高度必定大于left-1,右边界right的高度也必定大于right+1,且h是在left-right中最短的高。看透了这一点,我们就可以想办法来设计算法寻找并计算矩形。
方法一:左右扫描
以每一个柱子i的高度height[i]为矩形的高h,从i为中心向左右扫描找出left和right。
方法二:单调递增栈
借助辅助栈存储当前最大柱子高度对应的下标。当栈空或当前高度大于栈顶高度时,将元素入栈。
当柱子i小于栈顶元素p的高度时,i对应位置right+1,p的高度对应h,p在栈中的下一个元素s对应位置left-1。
通过这个方法还可以求区间最小值。
方法三:动态规划(最优)
建立数组lessFromLeft、lessFromRight。lessFromLeft[i]代表从i向左第一个高度小于i的元素的下标,也即对于i来说left的坐标;lessFromRight[i]代表从i向右第一个高度小于i的元素的下标,也即对于i来说right的坐标。利用动态规划的方法求解lessFromLeft、lessFromRight,再依次扫描求解矩形面积即可。
传送门:柱状图中最大的矩形
Given n non-negative integers representing the histogram’s bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].
The largest rectangle is shown in the shaded area, which has area = 10 unit.
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
import java.util.Stack;
/**
*
* Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
* 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
*
*/
public class LargestRectangleInHistogram {
//暴力法:以每一根柱子为中心向左右拓展获得最大区域
public int largestRectangleArea(int[] heights) {
int result = 0;
for(int i = 0; i < heights.length; i++){
int begin = i;
while(begin >= 0 && heights[begin] >= heights[i]){
--begin;
}
int end = i;
while(end < heights.length && heights[end] >= heights[i]){
++end;
}
if(heights[i] * (end - begin - 1) > result){
result = heights[i] * (end - begin - 1);
}
}
return result;
}
//单调递增栈法:利用辅助栈动态存储当前最大高度柱子对应下标
public int largestRectangleArea1(int[] heights){
Stack<Integer> stack = new Stack<>();
int maxArea = 0;
for(int i = 0; i <= heights.length; i++){
//最后一次扫描令柱子的高度为0,使栈中元素全部弹出
int height = i == heights.length ? 0 : heights[i];
//当栈空或当前高度大于栈顶高度时,将元素入栈。
if(stack.empty() || height >= heights[stack.peek()]){
stack.push(i);
}
//当当前高度小于栈顶高度时,可以计算并更新最大矩形面积。
//由于栈顶元素t高度比p小,i也比p高度小。因此必能构成从t至i以i-t-1为底,height[p]为高的矩形。
//若计算后当前高度依然小于栈顶高度,则继续计算。
else{
int curArea = heights[stack.pop()] * (stack.empty() ? i : i - stack.peek() - 1);
maxArea = curArea > maxArea ? curArea : maxArea;
--i;
}
}
return maxArea;
}
//单调递增栈写法2
public int largestRectangleArea11(int[] heights){
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int maxArea = 0;
for(int i = 0; i < heights.length; i++){
//弹出栈中所有不大于当前高度heights[i]的元素,计算矩形面积
while(stack.peek() != -1 && heights[stack.peek()] >= heights[i]){
maxArea = Math.max(maxArea, heights[stack.pop()] * (i - stack.peek() - 1));
}
stack.push(i);
}
//处理剩余栈中元素
while(stack.peek() != -1){
maxArea = Math.max(maxArea, heights[stack.pop()] * (heights.length - stack.peek() - 1));
}
return maxArea;
}
//记录每一个柱子在左扫描和右扫描下的最小高度
public int largestRectangleArea2(int[] heights){
if(heights.length == 0){
return 0;
}
//lessFromLeft[i]代表从i向左第一个高度小于i的元素的下标
//lessFromRight[i]代表从i向右第一个高度小于i的元素的下标
int[] lessFromLeft = new int[heights.length];
lessFromLeft[0] = -1;
int[] lessFromRight = new int[heights.length];
lessFromRight[heights.length - 1] = heights.length;
for(int i = 1; i < heights.length; --i){
int p = i - 1;
while(p >= 0 && heights[p] >= heights[i]){
p = lessFromLeft[p];
}
lessFromLeft[i] = p;
}
for(int i = heights.length - 2; i >= 0; --i){
int p = i + 1;
while(p >= 0 && heights[p] >= heights[i]){
p = lessFromRight[p];
}
lessFromRight[i] = p;
}
int maxArea = 0;
for(int i = 0; i < heights.length; ++i){
//以lessFromRight[i] - lessFromLeft[i] - 1为底,heights[i]为高构成的矩形是以i为中心的最大矩形
int curArea = heights[i] * (lessFromRight[i] - lessFromLeft[i] - 1);
maxArea = curArea > maxArea ? curArea : maxArea;
}
return maxArea;
}
}
#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#