LeetCode 面试题 16.11. 跳水板 85. 最大矩形 84. 柱状图中最大的矩形

面试题 16.11. 跳水板

你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。
返回的长度需要从小到大排列。
示例:
输入:
shorter = 1
longer = 2
k = 3
输出: {3,4,5,6}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/diving-board-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

两种长度的木板,k个,所有长度的可能中,短木板个数i从0到k,长木板从k到0,一共k+1中可能。
因为结果需要排序,只需把第一种可能(全为短木板)放在数组最前,而后依次把短木板换一个换成长木板即可(后一个的总长度是前一个总长度加上长短木板长度的差值)

  • 需要注意,
  • 题中所给条件,K有可能等于0,在这种情况,巧妇难为无米之炊,返回一个空数组
  • 长短木板长度有可能相等,此时把长木板换成短木板并没有变化,总长度只有一个可能
class Solution {
    public int[] divingBoard(int shorter, int longer, int k) {
        if(k==0){
            return new int[0];
        }else if(shorter==longer){
            return new int[]{shorter*k};
        }
        int[] ans=new int[k+1];
        int step=longer-shorter;
        ans[0]=shorter*k;
        for(int i=1;i<ans.length;i++){
            ans[i]=ans[i-1]+step;
        }
        return ans;
    }
}


85. 最大矩形

给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例:
输入:
[
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]
输出: 6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximal-rectangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

首先,这里说的“矩形” 严格意义上来说,可以说是点阵

在我眼里,把矩形看成一个一个的横线方便解题:
我们有如下的一个矩阵:

  • 我们先做一个统计:每个点开始往右,有多少个连续的“1”
  • 也就是计算,对每个点来说,它向右的“线”的“长度”


得到这个矩阵:

如上所说,这个矩阵描述了每一个点向右线段的长度,
那么,对于一列来说,比如说第一列(1,1,5,1),表达了这样的信息:

我们显然可以得到左边为这一列的所有可能矩形中,最大的一个
最简单粗暴的方式:两层循环遍历所有可能的上边的所在行和下边的所在行
对于一个特定的上边和下边,我们对应最大的面积就是,上边到下边的距离最短边
比如:对于第三行一行,最大面积应该是1
5;
但是, 对于第二行加第三行,最大面积是2*1;

ok,现在我们有了每一列为最左边所对应的最大矩形面积
如此遍历每一列就好了!

遍历每一列之后,我们当然就得到了我们的结果!

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if(matrix.length==0||matrix[0].length==0){
            return 0;
        }
        int x=matrix.length,y=matrix[0].length;
        int[][] count = new int[matrix.length][matrix[0].length];
        for(int i=x-1;i>=0;i--){
            for(int j=y-1;j>=0;j--){
                //如果不是在最右且char值为1,计数为左边计数+1
                if(j!=y-1&&matrix[i][j]=='1'){
                    count[i][j]=count[i][j+1]+1;
                }else if(j!=y-1){
                    //如果不在最右且char为0,则计数为0
                    count[i][j]=0;
                }else{
                    //如果在右边,取决于char值
                    if(matrix[i][j]=='1'){
                        count[i][j]=1;
                    }else{
                        count[i][j]=0;
                    }
                }
            }
        }
        int maxS=0;
        for(int j=0;j<y;j++){
            maxS=Math.max(maxS,h(0,j,x-1,count));
        }
        return maxS;
    }
    public int h(int I,int J, int I1,int[][] count){
        int max=0;
        int length=0;
        for(int i=I;i<=I1;i++){
            length=count[i][J];
            max=Math.max(max,length);
            for(int j=i+1;j<=I1;j++){
                length=Math.min(length,count[j][J]);
                max=Math.max(max,length*(j-i+1));
            }
        }
        return max;
    }
}


性能问题主要在,知道了各个线条的长度之后,如何找到列中的最大矩形,进而找到全局的最大矩形。
即 下一题性能的改善

84. 柱状图中最大的矩形

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

是上一题的一部分,把所有可能的左和右遍历一遍求出面积的最大值即可

class Solution {
    public int largestRectangleArea(int[] heights) {
        int maxS=0;
        int maxLength;
        for(int i=0;i<heights.length;i++){
            maxLength=heights[i];
            maxS=Math.max(maxLength,maxS);
            for(int j=i+1;j<heights.length;j++){
                maxLength=Math.min(maxLength,heights[j]);
                maxS=Math.max(maxS,maxLength*(j-i+1));
            }
        }
        return maxS;
    }
}


显然性能还有很大的提升空间
首先,我们知道,对于最大矩形,首先它应该满足以下两点:

  • 它的高度是应该等于某一列的高,且这一列显然是矩形对应的所有列中最“矮”的
  • 它的宽度应该最大,也就是说,它不能以现在的高度向左或者向右扩展

基于这两点,我们求出对于每一列,向左向右扩展宽度的最大值(以它自己的宽度)
不过显然,对于暴力遍历每一列能够扩展的宽度,效率是不够的

以题中所给的[2,1,5,6,2,3]为例,使用栈可以节省许多步骤:

  1. 0(2对应下标)入栈
  2. 由于0高度为2而1高度为1,0(2)高度对应矩形最右应该是0(它本身),而由于0(2)弹出后栈为空,因此最左我们记为-1(本来应该是0本身,但是方便计算底边长)
  3. 弹出0(2)并记录其左右后,1(1)入栈
  4. 2(5)比1(1)高,直接入栈
  5. 3(6)比2(5)高,直接入栈
  6. 4(2)比3(6)矮,准备出栈3(6),3(6)对应最右应该是现在手上的4(2)-1也就是3,最左应该是3(6)出栈后的index,2(因为只有在手上的高度高于栈顶高度才入栈,所以栈顶即最高,栈顶出栈后的栈顶记为向左延伸最远的地方)
  7. 4(2)比2(5)矮,准备出2(5),同上理,左为1(1),右为3
  8. 4(2)比1(2)高,4(2)入栈
  9. 5(3)比4(2)高,入栈
  10. 没有剩下的数了,开始清理栈中剩下的
  11. 5(3)出栈,左等于最大数组长度-1即5,右等于出栈后栈顶下标4
  12. 4(2)出栈 ,左等于最大数组长度-1即5,右等于出栈后栈顶下标1
  13. 1(1)出栈 ,左等于最大数组长度-1即5,右等于出栈后栈顶下标-1(因为没有元素了)

至此,我们得到了所有列对应矩形的最右边和最最左边
接下来,只要挨个计算矩形面积,取最大值即可!

class Solution {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
        int[] left = new int[n];
        int[] right = new int[n];
        Arrays.fill(right, n);
        Stack<Integer> stack = new Stack<Integer>();
        for (int i = 0; i < n; ++i) {
            while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
                right[stack.peek()] = i;
                stack.pop();
            }
            left[i] = (stack.isEmpty() ? -1 : stack.peek());
            stack.push(i);
        }
        
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
        }
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值