【问题标题】:Search a word in a matrix runtime comlexity在矩阵运行时复杂度中搜索单词
【发布时间】:2020-12-08 22:25:20
【问题描述】:

尝试分析以下算法的运行时复杂度:

问题:我们有一个 m * n 数组 A 由小写字母和目标字符串 s 组成。目的是检查目标字符串是否出现在A中。

算法:

for(int i = 0; i < m; i++){
    for(int j = 0; j < n; j++){
        if(A[i][j] is equal to the starting character in s) search(i, j, s)
    }
}

boolean search(int i, int j, target s){
    if(the current position relative to s is the length of s) then we find the target
    looping through the four possible directions starting from i, j: {p,q} = {i+1, j} or {i-1, j} or {i, j+1} or {i, j-1}, if the coordinate is never visited before
    search(p, q, target s)
}


我读到的一个运行时复杂性分析如下:

在数组A 中的每个位置,我们首先看到4 可能的探索方向。第一轮结束后,我们只有 3 个可能的选择,因为我们再也回不去了。所以最差的运行时复杂度是O(m * n * 3**len(s))

但是,我不同意这种分析,因为即使我们每轮只看到 3 个可能的选择,我们确实需要花费一次操作来检查该方向是否曾经被访问过。例如,在 java 中,您可能只使用一个布尔数组来跟踪一个地点是否曾被访问过,因此为了知道一个地点是否已被访问过,需要进行条件检查,这需要一次操作。我提到的分析似乎没有考虑到这一点。

运行时复杂度应该是多少?

更新:

假设目标字符串的长度为l,矩阵中给定位置的运行时复杂度为T(l)。然后我们有:

T(l) = 4 T(l- 1) + 4 = 4(3T(l - 2) + 4) + 4 = 4(3( 3T(l -3) + 4) + 4)) + 4 = 4 * 3 ** (l - 1) + 4 + 4 *4 + 4 * 3 * 4 + ...

+4 来自这样一个事实,即我们在每一轮中循环四个方向,除了递归调用自身 3 次。

【问题讨论】:

    标签: algorithm time-complexity


    【解决方案1】:

    运行时复杂度应该是多少?

    上面的分析是正确的,复杂度确实是O(m * n * 3**len(s))

    例如,在 java 中,您可能只使用一个布尔数组来跟踪一个地点是否曾被访问过,因此为了知道一个地点是否已被访问过,需要进行条件检查,这需要一次操作.

    这是正确的,与分析不矛盾。

    我们可以构造的最坏情况是矩阵仅填充一个字母a 和一个字符串aaaa....aaaax(许多字母a 和一个x 在末尾)。如果mnlen(s)足够大,几乎每次调用search函数都会产生3次自身的递归调用。每个调用都会产生另外 3 个调用(这给我们总共 9 个深度为 2 的调用),每个调用都会产生另外 3 个调用(这给我们总共 27 个深度为 3 的调用)等等。检查当前字符串字符、条件检查、产生递归都是O(1),所以整个search函数的复杂度是O(3**len(s))

    【讨论】:

    • 感谢您的回答,但我不太明白为什么检查当前字符串字符、条件检查、产生递归都是O(1)。如果我们将它们加在一起,我认为它仍然不是O(1)。我添加了一个更新来解释。
    • @penny Big-O 表示法不关心常量的乘法(或加法)。也就是说,O(a*f(n)+b)=O(f(n)) 代表任何 a&gt;0b&gt;0。见stackoverflow.com/a/22188943/11695625
    • 如果是这样,那么O(T(n)) = O(T(n - 1)) = ... = O(T(1)) = O(1) 感觉不太对劲。
    • @penny 确实不对。 ... 中的部分数量取决于n,因此如果n 受到限制(这意味着它本质上是一个常数),您实际上可以写出等式。但是 Big-O 表示法是关于渐近分析的,即 n 可能是任意大的,方程没有意义。您应该可以在n 上编写没有假设的(有限)方程以使其工作。
    【解决方案2】:

    解决方案是蛮力。我们必须触摸黑板上的每个点。这使得O(m*n) 操作。

    现在对于每个点,我们必须运行 dfs() 来检查单词是否存在。所以我们得到

     O(m * n * timeComplexityOf dfs)
    

    这是一个用 python 编写的 dfs。检查时间复杂度

            def dfs(r,c,i): 
                # O(1)
                if i==len(word):
                    return True
                # O(1)
                # set is implemented as a hash table.
                # So, time complexity of look up in a set is O(1)
                if r<0 or c<0 or r>=ROWS or c>=COLS or word[i]!=board[r][c] or (r,c) in path_set:
                    return False
                # O(1)
                path.add((r,c))
                # O(1)
                res=(dfs(r+1,c,i+1) or
                     dfs(r-1,c,i+1) or
                     dfs(r,c+1,i+1) or
                     dfs(r,c-1,i+1))
                # O(1)
                path.remove((r,c))
                return res
    

    由于我们 dfs 递归调用自身,请考虑调用堆栈上将有多少个 dfs 调用。在最坏的情况下,它将是单词的长度。这就是为什么

    O ( m * n * word.length)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 2015-10-07
      • 1970-01-01
      • 2011-09-18
      • 1970-01-01
      • 1970-01-01
      • 2022-06-19
      相关资源
      最近更新 更多