Algorithms: Rectangle related Questions

子问题 I:储水问题

11. Container With Most Water

从两边用两个指针一直遍历到中间。理论上,两边拥有最长的长,高度由两边中的较低的边决定。
关键是如何递增或递减。为了求最大的面积,当长度变小时,直觉上应该保留更长的边,将更小的边的index
递增或者递减,才有可能更新面积。
想明白以上,这道题就不难了。


42. Trapping Rain Water

首先,某个towel (bar)所能储存的水量其实是当前水桶的“短板” - 当前bar的高度决定的。但是,并不是所有的bar都能储水。所以我们首先需要判断这个bar能不能储水。如果能储水,就把水量加到要返回的水量总和当中。
怎么判断当前bar能不能储水呢?
这就是比较tricky的地方了。主要看这个bar的左边的所有bar中最高的bar是否能高过这个bar且右边的所有bar中最高的bar是否能高过这个bar。如果两边都满足,这个bar能储水。否则,直接跳过这个bar即可。

注意,每个bar的储水量计算方法是:当前的长度(1) * (两边的短板与当前bar的高度差)。




子问题 II:最大长方形问题

84. Largest Rectangle in Histogram

问题描述:

简单直接的方法是当遍历的柱子是递增的时候,继续遍历【1】。一旦遇到比下一个当前的小的情况(index还是停留在最高的柱子的地方)。然后,往后遍历每个前面的柱子(包括当前)求当前长(index - back + 1) * 遍历历史最低。遍历历史最低是每次遍历到新的柱子,比较当前高是否小于最小的历史。初始值是Integer.MAX_VALUE。


有一个Tricky的地方是,【1】的终止条件不仅仅是停止递增。还包括如果到了最后一个柱子。也就是说,无论如何,到了最后的柱子都要重新检查一遍。(以防最后的柱子无限高的极端情况)


85. Maximal Rectangle(动态规划)

这题会用到largest retangle in histogram,针对每一行用这个方法求面积
每行的状态数组表示当前的柱高
转换:dp[i][j] = matrix == '1' ? 1 + dp[i-1][j] : 0; 除了第一行;
设一个全局变量,返回最后的全局变量。



子问题 III:最小包围长方形问题

302. Smallest Rectangle Enclosing Black Pixels

这是一个二分搜索的问题。这题的思路很直接,从给的坐标出发。向左、向右、向上、向下出发寻找边界,接着用边界的坐标求出面积。寻找边界的时候利用一个定理:

If there are only one black pixel region, then in a projected 1D array all the black pixels are connected.

因为题目说了只有一个black region,所以,将每一列的黑点都投影到一行,他们必须是相连的。

所以,搜索列的方案是:如果遍历这一列没有黑点,证明走远了,往回走(j = mid)。否则,继续往前走。(i = mid + 1)。比较tricky的方法是用到了一个boolean来处理两边不同的情况。一个进步是用i = mid + 1(右边)。一个进步是用 j = mid(左边)。


子问题 IV:构造最接近正方形的长方形问题(因式分解)

492. Construct the Rectangle

给定一个面积,求其相差最小的两个因子。利用sqrt函数求得截掉小数的int。接着从这个int开始,递减找一个能整除area的数字。


11. Container With Most Water


Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.


Note: You may not slant the container and n is at least 2.


public class Solution {
    // 从两边用两个指针一直遍历到中间。理论上,两边拥有最长的长,高度由两边中的较低的边决定。
    // 关键是如何递增或递减。为了求最大的面积,当长度变小时,直觉上应该保留更长的边,将更小的边的index
    // 递增或者递减,才有可能更新面积。
    // 想明白以上,这道题就不难了。
    public int maxArea(int[] height) {
        int left = 0, right = height.length - 1;
        int res = 0;
        while (left < right) {
            int area = Math.min(height[left],height[right]) * (right - left);
            res = res < area ? area : res;
            if (height[left] > height[right]) --right;
            else ++left;
        }
        return res;
    }
}


42. Trapping Rain Water


Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.


For example, 
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.

public class Solution {
    public int trap(int[] height) {
        if (height == null || height.length < 3) {
            return 0;
        }
        
        int[] maxHeightLeft = new int[height.length];
        int[] maxHeightRight = new int[height.length];
        
        maxHeightLeft[0] = 0;
        maxHeightRight[height.length - 1] = 0;
        
        int maxHeight = 0;
        //fill in those two arrays
        for (int i = 1; i < height.length; i++) {
            maxHeight = 0;
            for (int j = i - 1; j > -1; j--) {
                maxHeight = height[j] > maxHeight ? height[j] : maxHeight;
            }
            maxHeightLeft[i] = maxHeight;
        }
        
        for (int i = 0; i < height.length - 1; i++) {
            maxHeight = 0;
            for (int j = i + 1; j < height.length; j++) {
                maxHeight = height[j] > maxHeight ? height[j] : maxHeight;
            }
            maxHeightRight[i] = maxHeight;
        }
        
        //simple logic
        int trap = 0;
        
        for (int index = 0; index < height.length; index++) {
            if (height[index] > maxHeightLeft[index] || height[index] > maxHeightRight[index]) {
                continue;
            }
            
            trap += (Math.min(maxHeightLeft[index], maxHeightRight[index]) - height[index]);
        }
        
        return trap;
    }
}




84. Largest Rectangle in Histogram


Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.


Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].


The largest rectangle is shown in the shaded area, which has area = 10 unit.


For example,
Given heights = [2,1,5,6,2,3],
return 10.


public class Solution {
    public int largestRectangleArea(int[] heights) {
        if (heights == null || heights.length == 0) {
            return 0;
        }
        
        if (heights.length == 1) {
            return heights[0];
        }
        
        int res = 0;
        for (int i = 0; i < heights.length; i++) {
            if (i < heights.length - 1 && heights[i] <= heights[i + 1]) {
                continue;
            } // 最后的坐标一样会跳出来重新算一遍
            
            int high = heights[i];
            for (int j = i; j >= 0; j--) {
                high = heights[j] < high ? heights[j] : high;
                int area = (i - j + 1) * high;
                res = (res < area) ? area : res;
            }
        }
        
        return res;
    }
}




85. Maximal Rectangle


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.


public class Solution {
    // 这题会用到largest retangle in histogram,针对每一行用这个方法求面积
    // 每行的状态数组表示当前的柱高
    // 转换:dp[i][j] = matrix == '1' ? 1 + dp[i-1][j] : 0; 除了第一行;
    // 设一个全局变量,返回最后的全局变量。
    public int maximalRectangle(char[][] matrix) {
        int maxArea = 0;
        
        if (matrix == null || matrix.length == 0
            || matrix[0] == null || matrix[0].length == 0) {
                return maxArea;
        }
        
        int row = matrix.length;
        int col = matrix[0].length;
        
        int[][] dp = new int[row][col];
        
        for (int t = 0; t < col; t++) {
            dp[0][t] = matrix[0][t] == '1' ? 1 : 0;
        }
        
        for (int i = 1; i < row; i++) {
            for (int j = 0; j < col; j++) {
                dp[i][j] = matrix[i][j] == '1' ? 1 + dp[i - 1][j] : 0;
            }
        }
        
        // calculate ares per row
        for (int i = 0; i < row; i++) {
            int area = largestArea(dp[i]);
            maxArea = maxArea < area ? area : maxArea;
        }
        
        return maxArea;
    }
    
    private int largestArea(int[] row) {
        if (row == null || row.length == 0) {
            return 0;
        }
        
        if (row.length == 1) {
            return row[0];
        }
        
        int res = 0;
        
        for (int i = 0; i < row.length; i++) {
            if (i < row.length - 1 && row[i] <= row[i + 1]) {
                continue;
            }
            int high = row[i];
            for (int j = i; j >= 0; j--) {
                high = high > row[j] ? row[j] : high;
                int area = high * (i - j + 1);
                res = area > res ? area : res;
            }
        }
        
        return res;
    }
}



302. Smallest Rectangle Enclosing Black Pixels
An image is represented by a binary matrix with 0 as a white pixel and 1 as a black pixel. The black pixels are connected, i.e., there is only one black region. Pixels are connected horizontally and vertically. Given the location (x, y) of one of the black pixels, return the area of the smallest (axis-aligned) rectangle that encloses all black pixels.


For example, given the following image:


[
  "0010",
  "0110",
  "0100"
]
and x = 0, y = 2,
Return 6.

public class Solution {
    public int[] constructRectangle(int area) {
        int[] ans = new int[2];
        if (area <= 0) {
            return ans;
        }
        
        if (area == 1) {
            ans[0] = 1;
            ans[1] = 1;
            return ans;
        }
        
        int first = (int)Math.sqrt(area);
        
        while (area % first != 0) {
            first--;
        }
        
        ans[0] = area / first;
        ans[1] = first;
        
        return ans;
    }
}



492. Construct the Rectangle


For a web developer, it is very important to know how to design a web page's size. So, given a specific rectangular web page’s area, your job by now is to design a rectangular web page, whose length L and width W satisfy the following requirements:


1. The area of the rectangular web page you designed must equal to the given target area.


2. The width W should not be larger than the length L, which means L >= W.


3. The difference between length L and width W should be as small as possible.
You need to output the length L and the width W of the web page you designed in sequence.
Example:
Input: 4
Output: [2, 2]
Explanation: The target area is 4, and all the possible ways to construct it are [1,4], [2,2], [4,1]. 
But according to requirement 2, [1,4] is illegal; according to requirement 3,  [4,1] is not optimal compared to [2,2]. 


public class Solution {
    // 这题的思路很直接,从给的坐标出发。向左、向右、向上、向下出发寻找边界,接着用边界的坐标求出面积
    private char[][] image;
    public int minArea(char[][] iImage, int x, int y) {
        image = iImage;
        int m = image.length, n = image[0].length;
        int left = searchColumns(0, y, 0, m, true);
        int right = searchColumns(y + 1, n, 0, m, false);
        int top = searchRows(0, x, left, right, true);
        int bottom = searchRows(x + 1, m, left, right, false);
        return (right - left) * (bottom - top);
    }
    private int searchColumns(int i, int j, int top, int bottom, boolean opt) {
        while (i != j) {
            int k = top, mid = (i + j) / 2;
            while (k < bottom && image[k][mid] == '0') ++k;
            if (k < bottom == opt)
                j = mid;
            else
                i = mid + 1;
        }
        return i;
    }
    private int searchRows(int i, int j, int left, int right, boolean opt) {
        while (i != j) {
            int k = left, mid = (i + j) / 2;
            while (k < right && image[mid][k] == '0') ++k;
            if (k < right == opt)
                j = mid;
            else
                i = mid + 1;
        }
        return i;
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值