在柱状图中找最大矩形——O(n)时间复杂度java实现
2012-10-08 16:47
585 查看
最近在刷leetcode,又碰到了这道题,想起来当时算法有些瑕疵,所以将最新的AC代码更新在最上面做个对比,具体思路见注释.
这次没有bug了 :)
@2016-03-07
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
最近在准备找工作,知道了这道题,用java实现了O(n)时间复杂度的算法。
具体题目如下:给一组非负的整数来表示一个柱状图,设计一个算法获得柱状图中最大矩形的面积。比如,输入如下数据:2,1,4,5,1,3,3 ,其中每个数表示一个柱状条的高度,柱状条的宽度为默认值1,则计算得最大矩形的面积为8。
思路:使用一个栈来保存输入柱状条,每个柱状条包含两个信息:(1)柱状条的高度(height);(2)柱状条的x坐标(index) 。数组中的柱状条按序准备入栈,入栈的条件:当入栈元素e的高度>=栈顶元素的高度时,元素e入栈;否则,将栈顶元素出栈,同时更新最大矩形maxValue的值。
更新maxValue的算法如下:
1. 计算以当前栈顶元素的高度为宽度的矩形的面积:tmpValue = topElement.height * (e.index - topElement.index);
2. 更新maxValue: maxValue = (maxValue > tmpValue) ? maxValue : tmpValue;
所有元素入栈完毕,将栈中剩余的元素依次出栈,同时按照相同的思路更新maxValue的值。
java实现:
所有数组元素需要一次进栈和一次出栈,所以总的时间复杂度为:O(n)
public class Solution { // 思路: 主要是使用一个栈来保存数组元素的下标,注意是保存‘下标’。 // 入栈和出栈的规则如下: // (1) 当栈为空,或者以栈顶元素tp为下标查到的heights[tp] <= heights[i]时(i为当前遍历的索引),入栈 // (2) 当栈顶元素tp对应的heights[tp] > heights[i]时,出栈,同时计算以heights[tp]为高,能得到的最大矩形面积 // (3) 当遍历完整个heights数组后,若栈不为空,则依次弹栈,同时以栈顶元素tp对应的heights[tp]为高,计算能得到的最大矩形面积 public int largestRectangleArea(int[] heights) { if (heights == null || heights.length == 0) { return 0; } Stack<Integer> stack = new Stack<Integer>(); int maxSize = 0; int i = 0; for (; i < heights.length; i++) { if (stack.empty() || heights[stack.peek()] <= heights[i]) { stack.push(i); } else { // 当前遍历元素heights[i] 比栈顶元素tp对应的heights[tp]小, 栈顶元素出栈 int tp = stack.pop(); int beginIndex = stack.empty() ? -1 : stack.peek(); // 当栈为空时,说明最大矩形的长度从下标0开始 // 所以将beginIndex设置为-1 maxSize = max(maxSize, heights[tp] * (i-1 - beginIndex)); i--; // 由于heights[i]元素还在栈外等候,还需要继续和栈顶元素进行比较,所以i-- } } while (!stack.empty()) { // 栈还不为空,对每个栈顶元素tp 计算以heights[tp]为高的矩形的最大面积, 并将栈顶元素出栈 int tp = stack.pop(); int beginIndex = stack.empty() ? -1 : stack.peek(); // 当栈为空时,说明最大矩形的长度从下标0到下标n-1, // 所以将beginIndex设置为-1 maxSize = max(maxSize, heights[tp] * (i-1 - beginIndex)); } return maxSize; } private int max(int a, int b) { return a > b ? a : b; } }
这次没有bug了 :)
@2016-03-07
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
最近在准备找工作,知道了这道题,用java实现了O(n)时间复杂度的算法。
具体题目如下:给一组非负的整数来表示一个柱状图,设计一个算法获得柱状图中最大矩形的面积。比如,输入如下数据:2,1,4,5,1,3,3 ,其中每个数表示一个柱状条的高度,柱状条的宽度为默认值1,则计算得最大矩形的面积为8。
思路:使用一个栈来保存输入柱状条,每个柱状条包含两个信息:(1)柱状条的高度(height);(2)柱状条的x坐标(index) 。数组中的柱状条按序准备入栈,入栈的条件:当入栈元素e的高度>=栈顶元素的高度时,元素e入栈;否则,将栈顶元素出栈,同时更新最大矩形maxValue的值。
更新maxValue的算法如下:
1. 计算以当前栈顶元素的高度为宽度的矩形的面积:tmpValue = topElement.height * (e.index - topElement.index);
2. 更新maxValue: maxValue = (maxValue > tmpValue) ? maxValue : tmpValue;
所有元素入栈完毕,将栈中剩余的元素依次出栈,同时按照相同的思路更新maxValue的值。
java实现:
import java.util.ArrayList; import java.util.List; import java.util.Stack; public class MaxRectangle { // 使用栈来保存每个柱状条,当当前准备入栈的柱状条的高度小于当前栈顶的柱状条高度时,先让栈顶元素出栈,同时计算最大的矩形大小 public int maxRectangleValue(int[] array) { if (array == null || array.length <= 0) return -1; int maxValue = 0; List<Element> inputList = new ArrayList<Element>(); int len = array.length; for (int i = 0; i < len; i++) { Element element = new Element(array[i], i); inputList.add(element); } // 开始入栈操作 Stack<Element> stack = new Stack<Element>(); for (Element e : inputList) { if (stack.empty()) stack.add(e); else { while (e.height < stack.peek().height) { // 出栈,并计算最大矩形大小 Element topElement = stack.pop(); int tmpValue = topElement.height * (e.index - topElement.index); // height * width if (tmpValue > maxValue) maxValue = tmpValue; if (stack.empty()) break; } // 进栈 stack.add(e); } } // 将堆栈中包含的所有元素出栈,同时更新最大的矩形大小 while (!stack.empty()) { Element topElement = stack.pop(); int tmpValue = topElement.height * ((len - 1) - topElement.index + 1); // height * width if (tmpValue > maxValue) maxValue = tmpValue; } return maxValue; } public static void main(String[] args) { int[] array = {2,1,4,5,1,3,3}; MaxRectangle mr = new MaxRectangle(); System.out.println(mr.maxRectangleValue(array)); } } class Element { public int height; // 每一个柱状条的高度(宽度为1) public int index; // 每个柱状条的x坐标值,代表它们出现的相对次序 public Element(int height, int index) { this.height = height; this.index = index; } }算法分析:
所有数组元素需要一次进栈和一次出栈,所以总的时间复杂度为:O(n)
相关文章推荐
- [java实现]找一个数组的最大和的连续子数组(时间复杂度 O(n))
- [java实现]找一个数组的最大和的连续子数组(时间复杂度 O(n))
- java中hashmap容器实现查找O(1)时间复杂度的思考
- 计数排序的思想,时间空间复杂度细致分析以及java源代码实现
- Java 用两个队列实现一个栈,要求top()的时间复杂度为O(1)
- 链表的java实现与时间和空间复杂度分析
- 八大排序算法思想,时间复杂度,稳定性、及其java实现
- 最大子列和问题的四种不同时间复杂度的算法实现
- 最大子数组之和(线性时间复杂度,C语言实现)
- 不同时间复杂度实现最大子段和
- java实现栈-输出最大值,最小值,时间复杂度O(1)
- 随笔:实现一个队列,使得取出最大值的时间复杂度较低
- 【算法数据结构Java实现】时间复杂度为O(n)的最大和序列
- 设计桟的 min、push以及pop的时间复杂度都是O(1) Java 实现
- ccf计算机协会模拟题-最大的矩形-Java实现
- O(1)时间复杂度实现入栈、出栈、获得栈中最小元素、获得栈中最大元素
- 【算法数据结构Java实现】递归的简单剖析及时间复杂度计算
- java实现求两个数的最大公约数
- 实现一个栈,要求Push(入栈),Pop(出栈),Min(返回最小值的操作)的时间复杂度为O(1)
- 372. 在O(1)时间复杂度删除链表节点--java