[Leetcode] 302. Smallest Rectangle Enclosing Black Pixels 解题报告

这篇博客主要介绍了LeetCode中的问题302,如何找到最小的矩形来包围图像中的所有黑色像素。作者提出了两种解决方案:1) 使用深度优先搜索(DFS),从给定的黑色像素位置开始搜索,时间复杂度为O(m*n),m和n是图像的高度和宽度。2) 使用二分查找法,时间复杂度更优,为O(mlogn + nlogm)。文章还给出了DFS和二分查找的代码实现。

题目

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 = 0y = 2,

Return 6.

思路

1、DFS:首先想到的就是深度优先搜索。从位置 (x, y) 开始深度搜索它的四个邻居,在搜索的过程中维护四个边界,最后返回四个边界所对应的面积即可。该算法的时间复杂度是O(m*n),其中m和n分别是图像的高度和宽度。DFS应该是一个可以通过面试的算法了,当然这道题目用BFS我觉得也是可以解决的。

2、二分查找:还有一个更加巧妙、时间复杂度更低的算法。1)采用二分法在[0, y]区间内搜索每一行,找出最先出现‘1’的那一列,这样就确定了左边界left;2)采用二分法在[y + 1, col_num)区间内搜索每一行,找出最后出现‘0’的那一列,这样就确定了右边界right;3)采用二分法在[left, right]区间内找出最先出现‘1’的那一行,这样就确定了上边界up;4)采用二分法在[left, right]区间内找出最后出现‘0’的那一行,这样就确定了下边界down。四个边界都确定之后,就可以计算并返回包围盒的面积了。假设图像的高度和宽度分别是m和n,则算法的时间复杂度是O(mlogn + nlogm)。在实现中为了减少代码行数,将不同搜索函数整合在一起了,不过总体思路就是这么简单。

代码

1、DFS:

class Solution {
public:
    int minArea(vector<vector<char>>& image, int x, int y) {        
        if(image.size() == 0 || image[0].size() == 0) {
            return 0;
        }
        left = up = INT_MAX, right = down = INT_MIN;
        int row_num = image.size(), col_num = image[0].size();
        vector<vector<bool>> visited(row_num, vector<bool>(col_num, false));
        for(int r = 0; r < row_num; ++r) {
            for(int c = 0; c < col_num; ++c) {
                dfs(image, visited, r, c);
            }
        }
        return (right - left + 1) * (down - up + 1);
    }
private:
    void dfs(vector<vector<char>>& image, vector<vector<bool>>& visited, int row, int col) {
        int row_num = image.size(), col_num = image[0].size();
        if(row < 0 || row >= row_num || col < 0 || col >= col_num || 
            visited[row][col] || image[row][col] == '0') {
            return;
        }
        left = min(left, col), right = max(right, col);
        up = min(up, row), down = max(down, row);
        visited[row][col] = true;
        dfs(image, visited, row - 1, col);
        dfs(image, visited, row + 1, col);
        dfs(image, visited, row, col - 1);
        dfs(image, visited, row, col + 1);
    }
    int left, right, up, down;
};

2、二分查找:

class Solution {
public:
    int minArea(vector<vector<char>>& image, int x, int y) {
        if(!image.size() || !image[0].size()) {
            return 0;
        }
        int row_num = image.size(), col_num = image[0].size();
        // find the leftmost '1' in the range [0, row_num]
        int left  = horizontalSearch(0,     y,          0, row_num, image, '1');
        // find the rightmost '1' in the range [0, row_num] by searching 0
        int right = horizontalSearch(y + 1, col_num,    0, row_num, image, '0');
        // find the upmost '1' in the range [left, right]
        int up    = verticalSearch(0,       x,          left, right, image, '1');  
        // find the downmost '1' in the range [left, right] by searching 0
        int down  = verticalSearch(x + 1,   row_num,    left, right, image, '0');   
        return (right - left) * (down - up);
    }
private:
    // the time complexity is O(log(end - start) * (bottom - up))
    int horizontalSearch(int start, int end, int top, int bottom, vector<vector<char>>& image, char target) {
        while(start < end) {
            int mid = start + (end - start) / 2;
            int temp_top = top;
            char found = '0';
            while(temp_top < bottom) {
                if (image[temp_top++][mid] == '1') {
                    found = '1'; 
                    break;
                }
            }
            if(target == found) {
                end = mid;
            }
            else {
                start = mid + 1;
            }
        }
        return start;
    }
    
    // the time complexity is O(log(end - start) * (right - left))
    int verticalSearch(int start, int end, int left, int right, vector<vector<char>>& image, char target) { 
        while(start < end) {
            int mid = start + (end - start) / 2;
            int temp_left = left;
            char found = '0';
            while(temp_left < right) {
                if(image[mid][temp_left++] == '1') {
                    found = '1'; 
                    break;
                }
            }
            if(target == found) {
                end = mid;
            }
            else {
                start = mid + 1;
            }
        }
        return start;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值