【数据结构与算法经典问题解析】直方图中最大矩形

出自第四章问题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;
	}
}
结果:






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