Toeplitz矩阵“是一个矩阵,其中每个从左到右的下降对角线是恒定的。”给定二进制矩阵M,是否有一种有效的算法来确定是否存在使其成为Toeplitz的行的排列?
例如,设置
M= [0 1 1]
[1 1 0]
[1 0 1]
如果您换掉第一行和第二行,则
[1 1 0]
[0 1 1]
[1 0 1]
这是Toeplitz。
在python中,您可以创建一个随机二进制矩阵,如下所示。
n = 10
h = 10
M = np.random.randint(2, size=(h,n))
我想将测试应用于M.
(注意矩阵M不需要是方形的。)
答案 0 :(得分:11)
此问题可以在线性O(h * w)时间内解决,其中h
是行数,w
是列数。
构造一个图形,其中每个顶点对应于(w-1)
- 长度子串,它可以是矩阵中某行的前缀或后缀。一个顶点可以对应于几个重复的子串。将这些顶点与h
边连接起来。每个边缘对应于矩阵的行。它从与该行前缀对应的顶点指向与该行后缀对应的顶点。
要确定某些行排列是否是Toeplitz矩阵,检查构造的图是否为欧拉图就足够了。要查找排列本身,只需在此图表中找到Eulerian path即可。
我们需要一些有效的方法来互连顶点和边缘。直接的方法假设比较每个行 - 子串对。由于O(h 2 * w)时间复杂度,这不是很有趣。
为矩阵行构建Generalized suffix tree(或后缀数组)只需要O(h * w)时间。此树允许在线性时间内互连顶点和边:深度为w-1
的每个内部节点代表一些(w-1)
- 长度子串(顶点);附加到此节点的每个叶子代表一些行的后缀(传入边缘);并且附加到此节点的子节点的每个叶子表示包含此子字符串的一些行作为前缀(传出边缘)。
其他替代方法是使用哈希映射。使用(w-1)
- 矩阵行的长度子字符串作为键和行索引列表对(对于此子字符串为prefix / suffix的行)作为值。与后缀树/数组方法相比,这允许更简单的实现,需要更少的内存(每个键只需要空间用于散列值和指向子串的开头),应该更快(平均)工作,但具有较差的最坏情况复杂性: ø(H 2 * W)。
答案 1 :(得分:4)
一种适用于小型矩阵的简单方法是:
Sort the rows of M
For each choice of start row
For each choice of end row
construct a Toeplitz matrix T from the given start and end row
Sort the rows of T and compare to M
If you find a match then T is a permutation of M that is Toeplitz
这是基于以下事实:一旦您知道了开始和结束行,就会对Toeplitz矩阵进行唯一定义。
然而,这种方法并不是特别有效。
M= [[0, 1, 1],
[1, 1, 0],
[1, 0, 1]]
n=len(M)
M2 = sorted(M)
for start in M2:
for end in M2:
v = end+start[1:]
T = [v[s:s+n] for s in range(n-1,-1,-1)]
if sorted(T)==M2:
print 'Found Toeplitz representation'
print T
打印
Found Toeplitz representation
[[0, 1, 1],
[1, 0, 1],
[1, 1, 0]]
Found Toeplitz representation
[[1, 0, 1],
[1, 1, 0],
[0, 1, 1]]
Found Toeplitz representation
[[1, 1, 0],
[0, 1, 1],
[1, 0, 1]]
答案 2 :(得分:3)
您可以对消除条件进行预初步检查:
此外,如果i和i + 1是两个相邻列,则:
如果sum(i+1) = sum(i) + 1
,那么我们知道列i中最底部的元素应为0,列(i + 1)中的最顶层元素应为1.
如果sum(i+1) = sum(i) - 1
,那么我们知道第i列中最底部的元素应为1,而第(i + 1)列中最顶部的元素应为0.
如果sum(i+1) = sum(i)
,那么我们知道第i列中最底层的元素应该等于列(i + 1)中最顶层的元素。
您还可以通过对行进行求和来进行类似的检查,并查看是否存在任何两个相邻行的总和之间的差异最多为1的排列。
当然,您仍然需要进行一些组合搜索,但上述过滤器可能会减少搜索方案。
这是因为你现在必须为每对相邻列搜索满足上述3个条件的一对(候选顶部和底部)行。
此外,如果行数远大于列数,则此优化不会非常有用。