【问题标题】:Find if a small matrix exists in a big matrix in O(n)在 O(n) 中查找一个小矩阵是否存在于一个大矩阵中
【发布时间】:2020-07-03 16:37:05
【问题描述】:

我在面试中被问到一个问题:

给定矩阵A和矩阵B,我必须编写一个程序来找出矩阵B是否存在于矩阵A中。

问题是我必须在O(n) 时间内完成。这是我想出的唯一方法:

public class Matrix {
    public static void main(String[] args) {
        boolean flag = false;
        int a[][] = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12},
                {13, 14, 15, 16}};

        int b[][] = {
                {11, 12},
                {15, 16}};

        for (int i = 0; i < a.length - b.length + 1; i++) {
            for (int j = 0; j < a[0].length - b[0].length + 1; j++) {
                if (a[i][j] == b[0][0]) {
                    flag = true;
                    for (int k = 0; k < b.length; k++) {
                        for (int l = 0; l < b[0].length; l++) {
                            if (a[i + k][j + l] != b[k][l]) {
                                flag = false;
                                break;
                            }
                        }
                    }
                    if (flag) {
                        System.out.println("i= " + i + " j= " + j);
                        return;
                    }
                }
            }
        }
    }
}

我不知道如何将其转换为O(n)

有没有什么技术可以搜索O(n)中的大矩阵A中是否存在小矩阵B

【问题讨论】:

  • 假设 O(n) 表示矩阵大小是线性的,这可以通过散列来完成,您可以尝试查看 this
  • n“外”矩阵的线性大小(即矩阵为n x n)还是“外矩阵”的元素数(即n = m x m)?首先,我会说这是不可能的。

标签: java algorithm matrix multidimensional-array submatrix


【解决方案1】:

您可以使用 2D 滚动哈希。

给定(大)输入矩阵 A[N][N] 和较小的输入矩阵 M[K][K],通过散列每行中的每个 K 连续元素来构造一个新矩阵 H1[N][N-K+1],如下所示:

 H1[i][j] = hash(A[i][j], A[i][j+1], ..., A[i][j+K-1])

如果您的哈希函数被选择为滚动哈希函数(查找),它会在线性时间内运行,因为您可以在 O(1) 时间内从 H1[i][j] 构造 H1[i][j+1]

接下来,通过构造一个新矩阵H2[N-K+1][N-K+1],对列进行哈希处理:

 H2[i][j] = hash(H1[i][j], H1[i+1][j], ..., A[i+K-1][j])

对较小的矩阵应用相同的过程(生成具有单个元素的矩阵)。

现在,将较小矩阵中的单个哈希值与H2 的每个元素进行比较,如果它们相等,则几乎可以肯定匹配(您可以逐个检查)。

【讨论】:

  • 嗯,但这是否考虑了构建哈希的成本?在我看来,H1 在内存中是 ~O(N²),因此构建它似乎需要 ~O(N²)(不考虑 k)
  • @norok2 有一个歧义:矩阵大小的线性时间意味着 O(N^2) 时间,因为矩阵的大小为 N^2。显然,解决这个问题的算法不可能是 O(N),正如您在回答中所说的那样。
【解决方案2】:

已编辑

假设您有一个大小为n x m 的矩阵A 和一个大小为k x l 的矩阵B,则在A 中查找B 出现的问题的简单时间复杂度为@987654335 @ 与 O(1) 内存要求。

一般来说,你可以很容易地证明你不能比O(n m)更好,通过考虑k = l = 1的情况,它需要检查包含矩阵的所有元素,所以O(n m)。这与搜索字符串算法不能(全局)超线性的原因相同。


我假设您对成为O(N) 的要求更恰当地转换为成为O(n m) 的要求。如果这是可能的,您可以假设类似的算法可以适用于具有O(n) 复杂度(n 是输入的大小)的字符串搜索问题,而与模式k 的大小无关。没有找到这样的算法(甚至可能存在)。出于这个原因,我倾向于相信,如果可能的话,您正在寻找的东西目前超出了人类的知识范围。


相反,根据string-search algorithms 文献,您的目标是达到O(n m + k l) 复杂性。

一种可能的方法是使前面提到的string-search algorithms 之一适应此问题,因此,您应该能够获得类似的时间复杂度和内存要求。

例如,您的算法和@PaulHankin answer 都是对Rabin-Karp algorithm 适应2D 情况的描述。 虽然您的版本使用了非常糟糕的哈希(每个矩阵的第一个元素),但如果您要计算更高级/更合适的哈希(如建议的那样,但未提供 - 至少在撰写 @PaulHankin answer 时),就像rolling hash,那么您将能够在大多数情况下跳过最里面的两个循环,而滚动哈希将确保您不会为算法增加额外的输入大小相关的复杂性,这将导致@ 987654346@ 时间复杂度(O(k l) 来自计算B 上的哈希)和O(1) 内存需求。

适应其他字符串搜索算法(如Knuth-Morris-Pratt (KMP) algorithmTwo-way string-search (2WSS) algorithm)可能需要对算法进行一些“线性化”(不仅仅是问题表述),这意味着使用模算术找出在所有情况下都正确偏移,这可能很乏味,但我看不出这是不可能的,或者会让你失去预期的复杂性。

另一种选择是调整字符串搜索算法以在每个维度上交错工作。但这再次证明与处理一些“线性化”问题一样困难。

这里的最后一条信息是,绝对有可能超越O(n m k l),最终达到O(n m + k l),但这并不容易。

【讨论】:

  • 你能解释一下如何线性化这个问题吗?你确定有可能吗?
  • 您已经展示了您打算如何线性化问题的输入,但是子矩阵不是这种线性化形式的连续字符,那么字符串搜索如何找到特定的子矩阵?
  • @PaulHankin ...这意味着算法中的一些+1必须是+offset才能确定。这就是我对最后一行的意思。
  • 你如何调整任何字符串搜索算法来做到这一点?您需要根据已经匹配的字符串的初始段数来选择 +1 或 +offset,但我相信这会破坏大多数算法的增量。我认为你正在滑过比你想象的更难的细节。如果没有的话,也许你可以勾勒出修改后的 KMP 的样子。
  • @PaulHankin 我并不是说适应很容易,正确跟踪所有偏移量会非常乏味。然而,我看不出这是不可能的原因。
猜你喜欢
  • 1970-01-01
  • 2014-10-16
  • 1970-01-01
  • 1970-01-01
  • 2017-10-08
  • 2019-02-06
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
相关资源
最近更新 更多