求條形圖中最大矩形的面積的兩種演算法
一.問題描述
給出一個條形圖,假設每個條形的底邊長為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次冪,比暴力演算法快了一個數量級。