1. 程式人生 > >在柱狀圖中找最大矩形——O(n)時間複雜度java實現

在柱狀圖中找最大矩形——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)