算法——二维数组中寻找边界最长的正方形边框(不包括内部)

给定一个方阵,其中每个单元(像素)非黑即白。设计一个算法,找出 4 条边皆为黑色像素的最大子方阵。
返回一个数组 [r, c, size] ,其中 r, c 分别代表子方阵左上角的行号和列号,size 是子方阵的边长。若有多个满足条件的子方阵,返回 r 最小的,若 r 相同,返回 c 最小的子方阵。若无满足条件的子方阵,返回空数组。
leetcode

解题思路:这道题和之前遇到的寻找最大正方形很类似,不同的是,这里只需要一个边框就行了,所以更加麻烦一些。

  • 首先通过DP计算以每个元素为起点,向下的和向右的最大边长;
  • 然后枚举所有点,计算最大正方形;
  • 枚举一个点的时候,再比较枚举另外两条边,这样就能获得一个最大的正方形。
class Solution {
    public int[] findSquare(int[][] matrix) {
        int n = matrix.length;
        if(n == 0) return new int[0];
        int m = matrix[0].length;

        int[][] row = new int[n + 1][m + 1];
        int[][] col = new int[n + 1][m + 1];
        int[] res = new int[3];

		// 计算每个点向下和向右的最大边长,从最后开始
        for(int i = n - 1; i >= 0; i--) {
            for(int j = m - 1; j >= 0; j--) {
                if(matrix[i][j] == 1) continue;

                row[i][j] = row[i][j + 1] + 1;
                col[i][j] = col[i + 1][j] + 1;
            }
        }

		// 枚举每个点的最大正方形
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < m; j++) {
            	// 获取以该点为顶底的可能的最大正方形边长
                int cur = Math.min(col[i][j], row[i][j]);
				// 小于当前答案,那就没必要再枚举了
                if(cur < res[2]) continue;
				// 再去从大到小枚举边长,是否能够成正方形
                for(int x = cur; x > 0; x--) {
                	// 查看对应的点的边长是否符合要求
                    if(Math.min(row[i + x - 1][j], col[i][j + x - 1]) >= x) {
                        if(res[2] < x) {
                        	// 更新答案
                            res = new int[]{i, j, x};
                        }
                        // 已经枚举到最大的边长了,就没必要再枚举小的了
                        break;
                    }
                }
            }
        }

        return res[2] == 0 ? new int [0] : res;
    }
}
posted @ 2020-11-27 16:50  lippon  阅读(204)  评论(0编辑  收藏  举报