题目难度: 中等
今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~
给定一个方阵,其中每个单元(像素)非黑即白。设计一个算法,找出 4 条边皆为黑色像素的最大子方阵。
返回一个数组 [r, c, size] ,其中 r, c 分别代表子方阵左上角的行号和列号,size 是子方阵的边长。若有多个满足条件的子方阵,返回 r 最小的,若 r 相同,返回 c 最小的子方阵。若无满足条件的子方阵,返回空数组。
[
[1,0,1],
[0,0,1],
[0,0,1]
]
[
[0,1,1],
[1,0,1],
[1,1,0]
]
[r,c]而言, left[r,c]是其作为终点的向左连续黑边长, 而up[r,c]是其作为终点的向上连续黑边长left[1,1]是 0, left[1,2]是 1, left[2,2]是 1up[1,1]是 0, up[1,2]是 2, up[2,2]是 3left[r,c]可以通过left[r,c-1]转移得到, 而up[r,c]可以通过up[r-1,c]转移得到O(N^3): 需要遍历方阵一遍 (O(N^2)), 然后内部需要遍历可能的边长 (O(N))O(N^2): 维护了两个包含所有格子的 dp 字典class Solution:
def findSquare(self, matrix: List[List[int]]) -> List[int]:
n = len(matrix)
res = []
# left[r,c]是格子[r,c]作为终点的向左连续黑边长
left = collections.defaultdict(int)
# up[r,c]是格子[r,c]作为终点的向上连续黑边长
up = collections.defaultdict(int)
for r in range(n):
for c in range(n):
if matrix[r][c] == 0:
# 当前格子是黑色, 更新其向左和向上连续黑边长
left[r, c] = 1 + left[r, c - 1]
up[r, c] = 1 + up[r - 1, c]
# mxedge是当前格子作为右下角可能形成的黑方阵的最大边长
mxedge = min(left[r, c], up[r, c])
sr, sc, edge = r, c, mxedge
while edge > 0:
# 从最大边长开始找, 检查左下角格子的向上连续黑边长和右上角格子的向左连续黑边长是否不小于当前边长
# sr是当前边长的上侧边的行号
sr = r - edge + 1
# sc是当前边长的左侧边的列号
sc = c - edge + 1
if min(left[sr, c], up[r, sc]) >= edge:
# 可以形成当前边长的黑方阵, 无需找更小的边长了
break
edge -= 1
# 当前方阵边长更长, 或者更满足要求, 更新最终结果
if not res or edge > res[2] or edge == res[2] and ([sr, sc] < res[:2]):
res = [sr, sc, edge]
return res
大家可以在下面这些地方找到我~😊