我需要在一个充满1和0的巨型文件中找到1的最大平方。我知道我必须使用动态编程。我将它存储在2D数组中。任何有关找到最大方块的算法的帮助都会很棒,谢谢!
示例输入:
1 0 1 0 1 0
1 0 1 1 1 1
0 1 1 1 1 1
0 0 1 1 1 1
1 1 1 1 1 1
答案:
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
到目前为止我的代码:
int Square (Sq[int x][int y]) {
if (Sq[x][y]) == 0) {
return 0;
}
else {
return 1+MIN( Sq(X-1,Y), Sq(X,Y-1), Sq(X-1,Y-1) );
}
}
(假设已经输入数组的值)
int main() {
int Sq[5][6]; //5,6 = bottom right conner
int X = Square(Sq[5][6]);
}
我如何从那里继续?
答案 0 :(得分:77)
以下是解决方案的草图:
对于每个单元格,我们将保留一个计数器,使用该单元格作为左上角可以制作多大的正方形。显然,所有带0的单元格都会有0作为计数。
从右下方的单元格开始迭代并向左下方移动,然后向上一行并重复。
每次扫描都这样做:
count=0
count=1
max_count
变量以跟踪到目前为止的最大数量。在遍历矩阵结束时,max_count
将具有所需的值。
复杂性不再是遍历矩阵的成本。
这是遍历后矩阵的样子。括号中的值是计数,即可以使用单元格左上角进行的最大正方形。
1(1) 0(0) 1(1) 0(0) 1(1) 0(0)
1(1) 0(0) 1(4) 1(3) 1(2) 1(1)
0(0) 1(1) 1(3) 1(3) 1(2) 1(1)
0(0) 0(0) 1(2) 1(2) 1(2) 1(1)
1(1) 1(1) 1(1) 1(1) 1(1) 1(1)
def max_size(mat, ZERO=0):
"""Find the largest square of ZERO's in the matrix `mat`."""
nrows, ncols = len(mat), (len(mat[0]) if mat else 0)
if not (nrows and ncols): return 0 # empty matrix or rows
counts = [[0]*ncols for _ in xrange(nrows)]
for i in reversed(xrange(nrows)): # for each row
assert len(mat[i]) == ncols # matrix must be rectangular
for j in reversed(xrange(ncols)): # for each element in the row
if mat[i][j] != ZERO:
counts[i][j] = (1 + min(
counts[i][j+1], # east
counts[i+1][j], # south
counts[i+1][j+1] # south-east
)) if i < (nrows - 1) and j < (ncols - 1) else 1 # edges
return max(c for rows in counts for c in rows)
答案 1 :(得分:8)
LSBRA(X,Y)
表示“最大正方形,右下角为X,Y”
伪代码:
LSBRA(X,Y):
if (x,y) == 0:
0
else:
1+MIN( LSBRA(X-1,Y), LSBRA(X,Y-1), LSBRA(X-1,Y-1) )
(对于边缘单元格,您可以跳过MIN部分,如果(x,y)不为0,则返回1。)
在“wave”中对角线穿过网格,如下所示:
0 1 2 3 4
+----------
0 | 1 2 3 4 5
1 | 2 3 4 5 6
2 | 3 4 5 6 7
3 | 4 5 6 7 8
或者,只要您填写边缘单元格,就可以从左到右,从上到下进行工作。
0 1 2 3 4
+----------
0 | 1 2 3 4 5
1 | 6 7 8 9 .
2 | . . . . .
3 | . . . . .
这样你就不会遇到以前没有计算过必要数据的计算 - 因此所有LSBRA()
“调用”实际上只是你先前计算结果的表查找(因此动态编程方面)。
为什么会有效
为了在X,Y处有一个右下角的正方形,它必须包含一个较小尺寸的重叠正方形,以触及其他3个角中的每个角。换句话说,要有
XXXX
XXXX
XXXX
XXXX
你还必须......
XXX. .XXX .... ....
XXX. .XXX XXX. ....
XXX. .XXX XXX. ....
.... .... XXX. ...X
只要你有3个(每个LSBRA支票),N尺寸的正方形加上当前的正方形也被“占用”,你将有一个(N + 1) - 尺寸的正方形。
答案 2 :(得分:3)
我想到的第一个算法是:
我不会向您展示实施,因为它非常简单,您的问题听起来像家庭作业。此外,有可能采用更有效的方法,因为如果输入非常大,这将变得很慢。
答案 3 :(得分:2)
让输入矩阵为M
:n x m
T[i][j]
是DP矩阵,其中包含方形右下角(i,j)
的最大正方形边。
填写表格的一般规则:
if (M[i][j] == 1) {
int v = min(T[i][j-1], T[i-1][j]);
v = min(v, T[i-1][j-1]);
T[i][j] = v + 1;
}
else
T[i][j] = 0;
结果方块大小是T
中的最大值。
填写T[i][0]
和T[0][j]
是微不足道的。
我不确定此算法是否可用于巨大文件,
但您不需要存储整个矩阵T
,只能存储当前行和上一行。
以下注释可以帮助解决一般想法:
答案 4 :(得分:1)
好的,效率最低但很简单的方法是:
选择第一项。检查是否为1,如果是,则为1x1平方。
检查下面一个,一个检查一个,如果是1,则检查第2行第2行,如果是1,2x2平方。
检查第3行col 1,col 2和col 3,加上第1行第3列,第2行第3列,如果是1,3x3。
所以基本上你一直在扩展行和col并检查其边界内的所有单元格。一旦你达到0,它就会被打破,所以你连续1点移动,然后重新开始。
在行尾,移至下一行。
直到结束。
你可能会看到那些适合while循环等的方式,以及如何使用&&
来检查0,当你看到它时,你或许也会注意到它是如何被加速的起来。但正如刚才提到的另一个答案,它听起来有点像家庭作业,所以我们会把实际的代码留给你。
答案 5 :(得分:1)
这里的关键是你可以使用动态编程跟踪区域的根而不是实际区域。
算法如下:
存储一个名为max-square的整数二维数组,其中索引i处的元素j表示它与i的平方大小,j是右下角。 (如果max [i,j] = 2,则表示索引i,j是大小为2 ^ 2 = 4的正方形的右下角)
对于每个索引i,j:
if 在i,j元素为0,然后将max-square i,j设置为0.
其他:
找到max-square [i - 1,j]和max-square [i,j - 1]和max-square [i - 1] [j -1]的最小。将max-square [i,j]设置为1 +最小值3.感应地,你最终会填充max-square数组。查找/或跟踪流程中的最大值,返回该值^ 2。
看看人们提出的这些解决方案: https://leetcode.com/discuss/questions/oj/maximal-square?sort=votes
答案 6 :(得分:0)
设N是2D阵列中的单元格数量。存在一种非常有效的算法来列出所有最大的空矩形。最大的空方块位于这些空矩形中的一个内部,并且一旦计算出最大空矩形的列表,就会发现它是微不足道的。可以在www.ulg.ac.be/telecom/rectangles以及源代码(未优化)中找到提出用于创建这样的列表的O(N)算法的论文。注意,存在证明(参见论文)最大空矩形的数量由N限制。因此,选择最大空方块可以在O(N)中完成,并且整个方法也是O(N)。实际上,这种方法非常快。实现很容易,因为整个代码不应超过40行C(列出所有最大空矩形的算法需要大约30行C)。