我有一个数组,其中填充了数字,以便它包含空元素和非空元素,实际上由几个数组组成。它可能看起来像这样:
0 ххх0ххх 0 0 0 0 0 0
0 xхххххх 0 0 0х хх
0 0хххх0х 0 0 0ххх
0 хх0х ххх 0 0 х0хх
0 ххх000х 0 0 ххх0
0 0 0 0 0 0 0 0 0 0 0ххх
0 0 0 0 0 0 0 0 0 0 хххх
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 xxxxx 0 0 0 0 0 0 0 0 0 xxxx 0 x 0 0 0
“0”表示空元素
“x”表示非空元素
一个人在这里很容易找到3个子阵列,但我想知道如何使用程序找到它们。困难在于子阵列不满,即存在空元素。 是否有算法将初始数组切割成子数组或者任何人都可以帮助我? 附:子阵列的坐标(x1,y1,x2,y2):{2,1,8,5} {11,2,14,7} {6,9,11,10}。也用粗体
突出显示答案 0 :(得分:5)
您可以使用联合查找数据结构在O(NM)时间内解决此问题。请按照以下步骤操作:
Step1
:在矩阵中为相邻的填充元素生成连续的水平线。并用不同的数字标记这些行。
对于这个改变的矩阵
0 ххх0ххх 0 0 0 0 0 0
0 xхххххх 0 0 0ххх
0 0ххх00 0 0 0ххх
0 0 0 0 0 0 0 0 0 0 хххх
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 x x x x x 0 0 0
0 0 0 0 0 x x x x 0 0 0 0 0
矩阵的不同行将成为:
0 1 1 1 0 2 2 2 0 0 0 0 0 0
0 3 3 3 3 3 3 3 0 0 0 4 4 4
0 0 5 5 5 5 0 0 0 0 0 6 6 6
0 0 0 0 0 0 0 0 0 0 7 7 7 7
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 8 8 8 8 8 0 0 0
0 0 0 0 0 9 9 9 9 0 0 0 0 0
Step2
:现在初始化一个Union Find数据结构,其中所有不同的行作为数据结构中的单独的簇/集。
Step3
:开始迭代矩阵的所有列。每当遇到新行的开头时,请检查该行的正上方或下方是否有某条线。如果在上方或下方存在这样的行,则将与数据结构中的相邻行对应的两个组合并。
Step4
:现在算法末尾有所有不同的线簇,您可以轻松计算簇的边界。因此,您拥有所有不同的子阵列。
运行时间: 考虑到我们使用加权快速联合查找数据结构,路径压缩提供O(α(n))时间(其中α是{{3用于联合操作。由于逆ackermann函数增长非常缓慢,我将其视为常数。O(NM)
编辑:此情况下描述的算法将失败(由评论中的用户beaker告知)
1 1 1 1 1
2 0 0 0 3
0 0 4 0 0
为了处理这些类型的情况,除了提到的数据结构之外,我们将维护一个包含每行的占用矩形的数组。因此,当我们将第2行与第1行合并时,第2行的值将变为0 ... 4,表示存在覆盖第二行的索引0到4的矩形。现在,当在步骤3中考虑第4行时,它将检查上方或下方的点是否被某个矩形覆盖。因此它将第4行的集群与第2行的集群合并。
算法的其他部分将保持不变,除了我们现在检查相邻点是否被某个矩形覆盖。
我们为所有行维护的额外信息将增加运行时间。每当我们在步骤3中考虑矩阵列时,我们可能必须进行额外的O(n)工作。因此,运行时间上升到O(N^2 * M)