柱状图中最大的矩形

leetcode中的题目链接

题目

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。
在这里插入图片描述
示例

输入: [2,1,5,6,2,3]
输出: 10

测试数据

public static void main(String[] args) {
		// TODO Auto-generated method stub
//		int f[]= {2,1,5,6,2,3};  //10
//		int f[]= {2,1,2}; //3
//		int f[]= {3,6,5,7,4,8,1,0};  //20
//		int f[]= {6,4,2,0,3,2,0,3,1,4,5,3,2,7,5,3,0,1,2,1,3,4,6,8,1,3};   //14
		int f[]= {4,2};
		System.out.println(largestRectangleArea(f));
	}

想复杂了的方法

 // 超时。。思路:记忆化数组存储从i到j的最小值,然后纵横遍历,获取最大矩形面积
		public static int memo[][];
		public static int  len;
		public static int largestRectangleArea(int[] heights) {
			len=heights.length;
			memo=new int[len][len];
			//初始化
			for(int i=0;i<len;i++) {
				Arrays.fill(memo[i], -1);
			}
			// 对角线赋值
			for(int i=0;i<len;i++) {
				memo[i][i]=heights[i];
			}
			//  记忆化只改变右上三角区域
			int i,j;
			for(j=1;j<len;j++) {
				for(i=j-1;i>=0;i--) {
					memo[i][j]=Math.min(memo[i+1][j], memo[i][j-1]);
				}
			}
	//		for(i=0;i<len;i++) {
	//			for(j=0;j<len;j++) {
	//				System.out.print(memo[i][j]);
	//				if(memo[i][j]<0) {
	//					System.out.print("  ");
	//				}
	//				else {
	//					System.out.print("   ");
	//				}
	//			}
	//			System.out.println();
	//		}
			// 水平
			int res=0,from,value;
			for(i=0;i<len;i++) {
				if(res<memo[i][i]) {
					res=memo[i][i];
				}
				if(i+1<len&&memo[i][i]>memo[i][i+1]) {
					from=i;value=memo[i][i+1];
				}
				else {
					from=i;value=memo[i][i];
				}
				for(j=i+1;j<len;j++) {
					if(memo[i][j]!=value) {
						if(res<(j-from)*value) {
							res=(j-from)*value;
						}
						if(memo[i][j]<value) {
							value=memo[i][j];
						}
						else {
							from=j;
							value=memo[i][j];
						}
					}
				}
				if(res<(len-from)*value) {
					res=(len-from)*value;
				}
			}
			//竖直
			for(j=1;j<len;j++) {
				if(j-1>=0&&memo[j-1][j]<memo[j][j]) {
					from=j;
					value=memo[j-1][j];
				}
				else {
					from=j;
					value=memo[j][j];
				}
				for(i=j-1;i>=0;i--) {
					if(memo[i][j]!=value) {
						if(res<(from-i)*value) {
							res=(from-i)*value;
						}
						if(memo[i][j]<value) {
							value=memo[i][j];
						}
						else {
							from=i;
							value=memo[i][j];
						}
						
					}
				}
				if(res<from*value) {
					res=from*value;
				}
			}
			return res;
	    }

暴力解决的优化版本

public static int largestRectangleArea(int[] heights) {
	int res=0;
	int min;
	for(int i=0;i<heights.length;i++) {
		min=heights[i];
		for(int j=i;j<heights.length;j++) {
			if(min>heights[j]) {
				min=heights[j];
			}
			if(res<min*(j-i+1)) {
				res=min*(j-i+1);
			}
		}
	}
	return res;
}

分治思想实现

  • 思路:先找到其中最小的(如果有多个最小的,随便哪一个),然后三种情况(最小的乘以最大长度,左边子串最长,右边子串最长)。因为是同类型的,可以通过递归实现。
public static int largestRectangleArea(int[] heights) {
return downSizing(heights, 0, heights.length-1);
}

public static int downSizing(int []f,int from,int to) {
	if(from>to)
		return 0;
	int min=f[from],pos=from;
	for(int i=from+1;i<=to;i++) {
		if(f[i]<min	) {
			min=f[i];
			pos=i;
		}
	}
	int min_count=f[pos]*(to-from+1);
	int left_count=downSizing(f, from, pos-1);
	int right_count=downSizing(f, pos+1, to);
	if(min_count>=left_count&&right_count<=min_count) {
		return min_count;
	}
	else if(left_count>=min_count&&left_count>=right_count) {
		return left_count;
	}
	else {
		return right_count;
	}
}

栈解决(官方的牛皮方法)

  • 我的理解:栈中存放原数组下标。且栈顶到栈底中的数组下标对应的值是降序的。一旦不满足该条件,则弹出栈顶元素,直至满足为止。每次弹出栈顶元素都要计算最大矩形面积。
  • 理由:降序可以划分边界,之后入栈则又是一个边界(入栈的数据要小于栈顶元素)。两个边界之间的区域即为栈顶元素的面积。
public int largestRectangleArea(int[] heights) {
      Stack < Integer > stack = new Stack < > ();
      stack.push(-1);
      int maxarea = 0;
      for (int i = 0; i < heights.length; ++i) {
          while (stack.peek() != -1 && heights[stack.peek()] >= heights[i])
              maxarea = Math.max(maxarea, heights[stack.pop()] * (i - stack.peek() - 1));
          stack.push(i);
      }
      while (stack.peek() != -1)
          maxarea = Math.max(maxarea, heights[stack.pop()] * (heights.length - stack.peek() -1));
      return maxarea;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值