[LeetCode]Maximal Rectangle

题目:Maximal Rectangle

找到最大的全1矩阵。

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

 思路:

要求上面的解,先看下面的问题:

一个数组A[]={5,6,7,8,3};对应如下的直方图,求他的最大矩形的面积。

普通的思路,就是循环遍历,i=0~a.length-1;

然后里面从j=i~a.length-1,在最里层循环中,找到i到j的最小高度,求出它的矩阵面积,然后和最大值比较。

如此就能找到最大面积。

    private int largestRectangleArea(int[] height){
        int[] min = new int[height.length];//记录i~j的最小高度
        int max = 0;
        for (int i = 0; i < height.length; i++) {
            //最好的情况都无法超过最大面积,则跳过
            if(height[i] > 0 && max/height[i] >= height.length - i)continue;
            for(int j = i;j < height.length;j++){
                //找到i到j的最小高度
                if(i == j)min[j] = height[j];
                else if(height[j] < min[j - 1])min[j] = height[j];
                else min[j] = min[j - 1];
                //i到j的矩阵面积
                int curArea = min[j]*(j - i + 1);
                if(curArea > max) max = curArea;
            }
        }
        return max;
    }

用栈可以优化它的搜索速度。

1) 遍历高度数组,当数组的值是递增(即当前的高度大于栈顶的元素对应的高度)的状态或栈为空,就将当前高度下标入栈,下标加1。

2) 当数组元素不是递增时,即当前的高度小于栈顶元素对应的高度时,弹出该元素,求当前数组元素的前一个元素与当前栈顶元素的矩形面积Height[stack.peek()]*(i - stack.peek() - 1)。

3) 比较该面积和最大面积。

直到1) 再次满足,则入栈。

private int largestRectangleArea2(int[] height){
        Stack<Integer> stack = new Stack<Integer>();
        int newHeight[] = new int[height.length + 1];
        newHeight = Arrays.copyOf(height, height.length + 1);
        int i = 0,max = 0,num;
        while(i < newHeight.length){
            if(stack.isEmpty() || newHeight[stack.peek()] <= newHeight[i])//栈空或非递增则入栈
                stack.push(i++);
            else{//出栈
                int index = stack.pop();
                num = stack.isEmpty() ? i : i - stack.peek() - 1;
                max = Math.max(max, newHeight[index]*num);//求面积并取最大
            }
        }
        return max;
    }

有了上面的算法,就可以了求解Maximal Rectangle的问题了。

每一行遍历二维数组,按照下面的规则刷新数组的值:Arr[i][j]=Arr[i-1][j]+Arr[i][j] (Arr[i][j] > 0);

这样就可以得到每一行的直方图,再调用上面的方法求得最大面积。

package com.example.medium;

import java.util.Arrays;
import java.util.Stack;

/**
 * Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.
 * For example, given the following matrix:
 * 1 0 1 0 0
 * 1 0 1 1 1
 * 1 1 1 1 1
 * 1 0 0 1 0
 * Return 6.
 * @author FuPing
 *
 */
public class MaximalRectangle {
    private int largestRectangleArea(int[] height){
        int[] min = new int[height.length];//记录i~j的最小高度
        int max = 0;
        for (int i = 0; i < height.length; i++) {
            //最好的情况都无法超过最大面积,则跳过
            if(height[i] > 0 && max/height[i] >= height.length - i)continue;
            for(int j = i;j < height.length;j++){
                //找到i到j的最小高度
                if(i == j)min[j] = height[j];
                else if(height[j] < min[j - 1])min[j] = height[j];
                else min[j] = min[j - 1];
                //i到j的矩阵面积
                int curArea = min[j]*(j - i + 1);
                if(curArea > max) max = curArea;
            }
        }
        return max;
    }
    private int largestRectangleArea2(int[] height){
        Stack<Integer> stack = new Stack<Integer>();
        int newHeight[] = new int[height.length + 1];
        newHeight = Arrays.copyOf(height, height.length + 1);
        int i = 0,max = 0,num;
        while(i < newHeight.length){
            if(stack.isEmpty() || newHeight[stack.peek()] <= newHeight[i])//栈空或递增则入栈
                stack.push(i++);
            else{//出栈
                int index = stack.pop();
                num = stack.isEmpty() ? i : i - stack.peek() - 1;
                max = Math.max(max, newHeight[index]*num);//求面积并取最大
            }
        }
        return max;
    }
    public int maximalRectangle(char[][] matrix) {
        if(matrix == null || matrix.length == 0)return 0;
        int[][] intMatrix = new int[matrix.length][matrix[0].length];
        for (int i = 0; i < intMatrix.length; i++) {//转换成int的二维数组
                for (int j = 0; j < intMatrix[0].length; j++) {
                    intMatrix[i][j] = matrix[i][j] - 48;
                }
            }
        for(int j = 0;j < intMatrix[0].length;j++){//将每行转换成直方图
            for (int i = 1; i < intMatrix.length; i++) {
                if(intMatrix[i][j] != 0)//当前元素非零时,统计当前元素上面不为1的高度
                    intMatrix[i][j] += intMatrix[i - 1][j];
                }
        }
        int max = 0,lineMax = 0;
        for (int i = 0; i < intMatrix.length; i++){
            lineMax = largestRectangleArea2(intMatrix[i]);//求每一行的最大面积
            if(lineMax > max)max = lineMax;
        }
      return max;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        /*char[][] matrix = new char[][]{{'1','1','1','1','1','1','1','0'},
                {'1','1','1','1','1','1','1','0'},
                {'1','1','1','1','1','1','1','0'},
                {'1','1','1','1','1','0','0','0'},
                {'0','1','1','1','1','0','0','0'}};*/
        char[][] matrix = new char[][]{{'1','0','1','0','0'},
        {'1','0','1','1','1'},
        {'1','1','1','1','1'},
        {'1','0','0','1','0'}};
        for(char[] a : matrix){
            for(char ch :a)
                System.out.print(ch);
            System.out.println();
        }
        MaximalRectangle rectangle = new MaximalRectangle();
        int area = rectangle.maximalRectangle(matrix);
        System.out.println(area);

    }

}

 题目:Maximal Square

找到最大的全1方阵。

思路:

首先按照上面的方法的到每一行的高度直方图,然后求行最大方阵,最后比较每个行最大方阵,得到最大的方阵。

int LeetCode::maximalSquare(vector<vector<char>>& matrix){
    if(!matrix.size() || !matrix.at(0).size())return 0;//边为0
    vector<int>height(matrix.at(0).size() + 1, 0);//比matrix宽1,这样可以保证最后的一个数为0使得栈最后一定能清空
    int maxArea = 0;
    for (size_t i = 0; i < matrix.size(); i++){
        for (size_t j = 0; j < matrix.at(i).size(); j++){
            if (matrix.at(i).at(j) == '1'){//在上一行的height基础上加一
                height.at(j) += 1;
            }
            else{//从零开始
                height.at(j) = 0;
            }
        }
        //一行的高度计算完,下面求一行的最大面积
        int j = 0, width = 0;
        stack<int>s;
        while (j < height.size()){
            if (s.empty() || height.at(s.top()) <= height.at(j)){//栈空或递增时入栈
                s.push(j);
                ++j;
            }
            else{
                int pos = s.top();
                s.pop();
                width = s.empty() ? j : j - s.top() - 1;//用当前坐标j去减,数组下标从零开始,所以要再加一
                width = min(width, height.at(pos));//宽高中选择较小的作为正方形的边
                maxArea = max(width*width, maxArea);//求正方形的面积
            }
        }
    }
    return maxArea;
}
原文地址:https://www.cnblogs.com/yeqluofwupheng/p/6685553.html