1. 程式人生 > >求條形圖中最大矩形的面積的兩種演算法

求條形圖中最大矩形的面積的兩種演算法

一.問題描述


       給出一個條形圖,假設每個條形的底邊長為1,以相鄰的若干個條形中最短的條形的高度為一條邊的長度,再把它們的底邊相加作為另一條邊的長度可得到一個矩形,如圖中紅框所示,現在要求出最大矩形的面積。

二.兩種演算法

2.1暴力演算法

      窮舉所有的情況,以上圖為例,先計算出僅包含1個條形的矩形中的面積,圖中共有13個條形,故共有13個矩形僅包含一個條形,再計算所有包含2個條形的矩形的面積,共12個矩形,再計算所有包含3個條形的矩形的面積,共11個矩形,……最後計算包含13個條形的矩形的面積,只有1個矩形。比較所有矩形的面積,找出面積最大的那個。

2.2一種優化演算法

      這種演算法的思路是先把所有的矩形分類,分類標準是這樣:所有矩形分成13類,第1類矩形以圖中第1個條形的高度為最小高度,第2類矩形以圖中第2個條形的高度為最小高度,……第13類矩形以第13個條形的高度為最小高度。如果把每種分類中的矩形看做1個集合,則這13個集合的並集一定是全集(既所有矩形的集合),所以這種分類一定是完備的,雖然它們的交集可能不為空,然後在每一類矩形中找到最大的那個,共13個,最後在這13個矩形中找出一個最大的即可。該演算法在計算每種分類中的最大矩形時,只需以該分類中的最低條形為中心向兩邊擴充套件,直到遇到比該條形的高度要低的條形為止,夾在中間的部分即為該分類下的最大矩形。

三.演算法實現(基於java語言)

package com.algorithm.histogramarea;


public class Histogram {
	int[] height=new int[]{10,6,7,8,9,3,3,11,15,19,1,5,8};
	
	public static class MaxArea{
		private int begin;
		private int end;
		private int maxArea;
		public MaxArea(){
			begin=0;
			end=0;
			maxArea=0;
		}
		public int getBegin() {
			return begin;
		}
		public void setBegin(int begin) {
			this.begin = begin;
		}
		public int getEnd() {
			return end;
		}
		public void setEnd(int end) {
			this.end = end;
		}
		public int getMaxArea() {
			return maxArea;
		}
		public void setMaxArea(int maxArea) {
			this.maxArea = maxArea;
		}
		public String toString(){
			return "MaxArea is "+ maxArea+";The begin index is "+ begin +",the end index is" +end+".\n";
		}
	}
	
	private int findMinHeight(int step,int begin){
		int index=begin;
		int temp=height[index];
		while(step>1){
			if(temp>height[begin+step-1]){
				index=begin+step-1;
				temp=height[index];
			}
			step--;
		}
		return temp;
	}
	public MaxArea findMaxArea(){//演算法一 暴力演算法
		MaxArea maxArea=new MaxArea();
		int step=1;
		while(step<=height.length){
			for(int i=0;i<=height.length-step-1;i++){
				MaxArea maxArea2=new MaxArea();
				maxArea2.setBegin(i);
				maxArea2.setEnd(i+step-1);
				maxArea2.setMaxArea(findMinHeight(step,i)*step);
				if(maxArea.getMaxArea()<maxArea2.getMaxArea())
					maxArea=maxArea2;
			}
			step++;
		}
		
		return maxArea;
	}
	
	public MaxArea findMaxArea2(){//演算法二 基於分類思想
		MaxArea maxArea=new MaxArea();
		int indexOfLowestBar=0;
		while(indexOfLowestBar<13){
			int left=indexOfLowestBar-1;
			while(left>=0&&height[left--]>=height[indexOfLowestBar]);
			if(left<0)
				left+=1;
			else
				left+=2;
			int right=indexOfLowestBar+1;
			while(right<=12&&height[right++]>=height[indexOfLowestBar]);
			if(right>12)
				right-=1;
			else
				right-=2;
			if(maxArea.getMaxArea()<(right-left+1)*height[indexOfLowestBar]){
				maxArea.setBegin(left);
				maxArea.setEnd(right);
				maxArea.setMaxArea((right-left+1)*height[indexOfLowestBar]);
			}
			indexOfLowestBar++;
		}
		return maxArea;
	}
	
	public static void main(String[] args){
		Histogram histogram=new Histogram();
		long start;
		long end;
		long interval;
		
		start=System.nanoTime();
		MaxArea maxArea=histogram.findMaxArea();
		end=System.nanoTime();
		interval=end-start;
		System.out.println(maxArea+" wasted time is "+interval+" millseconds\n");
		
		start=System.nanoTime();
		MaxArea maxArea2=histogram.findMaxArea2();
		end=System.nanoTime();
		interval=end-start;
		System.out.println(maxArea2+" wasted time is "+interval+" millseconds\n");
	}
}

四.時間複雜度分析


      上圖是兩種演算法的執行結果,可見所求的最大矩形是相同的(注意這裡的index從0開始,圖中是從1開始),但暴力演算法明顯慢於第二種演算法。

具體分析的話,暴力演算法的時間複雜度為n的3次冪,計算過程如下:


      顯然的,第二種演算法的時間複雜度在最壞情況下也僅為n的2次冪,比暴力演算法快了一個數量級。