【數據結構與算法經典問題解析】直方圖中最大矩形

出自第四章問題24

問題24 直方圖中的最大矩形:   直方圖是由排列在同一基線上的一系列矩形組成的多邊形。爲了簡單起見,假設這些矩形的寬度相等但高度可能不同。例如,下圖1給出了一個直方圖,其中各個矩形的高度爲3、2、5、6、1、4、4,寬度爲標準1單位。當給定了一個保存所有矩形高度的數組時,如何找到其中最大的矩形。對於給定的例子,最大矩形如圖2陰影部分所示:

 圖1

圖2


解答:不完整子問題棧的線性搜索: 有很多種方法解決這個問題。Judege給出了一個基於棧求解問題的方法。首先按照從左到右的次序來處理元素,並將已經開始但尚未完成的子直方圖保存在棧中。如果棧爲空,通過將元素壓入棧來開啓一個字問題。否則,將元素與棧頂元素比較。如果新元素較大,那麼將其入棧。如果兩者相等,跳過,處理下一個元素。

    如果新元素較小,那麼用棧頂元素更新最大區域,並結束最頂層的子問題,然後刪除棧頂元素,保持當前新元素並重覆上述這個過程(繼續比較)。這樣,所有的子問題都會結束,直至棧爲空,或者棧頂元素小於或等於新元素,導致上述行爲。若所有元素都被處理過而棧仍然不爲空,那麼用棧頂元素更新最大區域來結束剩餘的子問題。

僞代碼如下:

public class StackItem{
	public int height;
	public int index;
}

int MaxRectangleArea(int A[], int n){
	long maxArea = 0;
	if(A == null || A.length ==0)
		return maxArea;
	Stack<StackItem> S = new Stack<StackItem>();
	S.push(new Integer.MIN_VALUE, -1);
	for(int i = 0; i <= n; i++){
		StackItem cur = new StackItem((i < n ? A[i] : Integer.MIN_VALUE), -1);
		if(cur.height > S.top().height){
			S.push(cur);
			continue;
		}
		while(S.size > 1){
			StackItem prev = S.top();
			long area = (i - prev.index)*prev.height;
			if(area > maxArea)
				maxArea = area;
			prev.height = cur.height;
			if(prev.height > S.get(S.size() - 2).height){
				break;
			}
			s.pop()
		}
	}
	return maxArea;
}


思考: 感覺這個解法有問題,當處理{8,7,6},這樣的遞減數組時,會出錯。下面是我修改後的代碼:

package com.stack;

import java.util.Stack;

public class MaxRectangleArea {
	/**
	 * 直方圖中最大矩形問題
	 * 主要思路是:將所有數組以非遞減循序存到棧中,當cur小於棧頂元素時,
	 * 將棧中所有小於cur的值替換成cur,並計算替換的這些值所能組成的最大的矩形面積;
	 * @param arr
	 * @return
	 */
	public static int getMaxRA(int[] arr){
		int maxArea = 0;
		if(arr == null || arr.length == 0)
			return maxArea;
		Stack<StackItem> ll = new Stack<StackItem>();
		ll.push(new StackItem(Integer.MIN_VALUE, -1));//開頭填入一個最小值看,while循環裏有用
		for(int i = 0; i <= arr.length; i++){
			//當i=length時說明數組已經遍歷完畢,填入一個最小值使得進入while循環,並求出棧中存儲的數組最大矩形面積
			StackItem cur = new StackItem(i < arr.length ? arr[i] : Integer.MIN_VALUE, i);
			//當cur當前值不小於棧頂值時,存入棧
			if(ll.lastElement().height <= cur.height){
				ll.push(cur);
				continue;
			}
			//當cur小於棧頂值prev時,計算prev到cur的矩形面積,並與最大矩形面積maxArea比較,
			//拋出棧頂值,直到棧頂值小於當前值cur
			int j = 0;
			while(ll.size() > 1){
				j++;
				StackItem prev = ll.pop();
				int area = (i - prev.index)*prev.height;
				if(area > maxArea)
					maxArea = area;
				if( ll.lastElement().height < cur.height)
					break;
			}
			//將拋出的值的位置用cur代替存入棧中,保持棧數據不遞減
			for(;j >= 0; j--){
				ll.push(new StackItem(cur.height, cur.index - j));
			}
		}
		return maxArea;
	}
	public static void main(String[] args) {
		int[] a = {8, 7, 5, 9, 3, 8, 7, 6, 5, 4};
		System.out.println("最大矩形面積爲: " + getMaxRA(a));
	}
}

class StackItem {
	public int height;
	public int index;
	
	public StackItem(int height, int index){
		this.height = height;
		this.index = index;
	}
}
結果:






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章