在柱状图中找最大矩形——O(n)时间复杂度java实现


最近在刷leetcode,又碰到了这道题,想起来当时算法有些瑕疵,所以将最新的AC代码更新在最上面做个对比,具体思路见注释.


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)

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值