【问题标题】:What's the runtime complexity of this code which contains four recursive calls?这段包含四个递归调用的代码的运行时复杂度是多少?
【发布时间】:2020-07-24 02:35:46
【问题描述】:

它具有 4 个递归函数的运行时复杂度是多少。

def func(arr,i,j,N):

  if i==N or j==N or i<0 or j<0: 
     return
  if arr[i][j]==1 or arr[i][j]=='X': 
     return

  arr[i][j]='X' 

  func(arr,i,j+1,N) 
  func(arr,i,j-1,N) 
  func(arr,i+1,j,N) 
  func(arr,i-1,j,N) 

  return(arr)

【问题讨论】:

    标签: algorithm recursion data-structures time-complexity big-o


    【解决方案1】:

    是 O(N^2)。每个单元格的每个邻居最多访问一次,因此最多有 4N(N-1) 个函数调用(不包括超出范围的函数调用,其中最多有 4N 个)。您可以添加一个计数器,每次调用 func 进行检查时都会递增。

    【讨论】:

      【解决方案2】:

      将网格想象成一个图形,网格点为顶点,边为网格相邻点之间的线段。

      节点的数量是N^2,你访问每个节点,所以算法必然是\Theta(N^2)。这样做时,您只跟踪每个边一次(第一次访问边后,两个端点都标记为1X,因此对于任何端点,程序流都不会再次到达递归调用)。

      边数为2N(N-1)。因此算法在O(N^2) 中运行。

      【讨论】:

        【解决方案3】:

        让我们首先采用数据分析方法。我们可以尝试用较小的 N 运行函数并寻找模式。

        import numpy as np
        
        
        global call_cnt
        
        def cc(arr,i,j,N):
        
          global call_cnt
        
          call_cnt += 1
          #print(call_cnt)
        
          if i==N or j==N or i<0 or j<0:
             return
          if arr[i][j]==1 or arr[i][j]=='X':
             return
        
          arr[i][j]='X'
        
          cc(arr,i,j+1,N)
          cc(arr,i,j-1,N)
          cc(arr,i+1,j,N)
          cc(arr,i-1,j,N)
        
          return(arr)
        
        
        n_On = []
        
        for i in range(1,30):
          global call_cnt
        
          call_cnt = 0
        
          cc(np.zeros((i,i)).tolist(), 0, 0, i)
        
          print(call_cnt)
          n_On.append(call_cnt)
        
        import matplotlib.pyplot as plt
        
        plt.plot(n_On)
        plt.show()
        
        
        
        1. 我们已经用非 1 值初始化了数组,因此我们不满足基本情况 arr[i][j] == 1,因此程序将在最坏的情况下运行。

        2. 在 29 之后,我们得到了最大的递归深度,所以我们只选择了 1-29 作为我们的 N。

        3. 绘制每个 N 的总调用次数后,我们得到此图。

        5
        17
        37
        65
        101
        145
        197
        257
        325
        401
        485
        577
        677
        785
        901
        1025
        1157
        1297
        1445
        1601
        1765
        1937
        2117
        2305
        2501
        2705
        2917
        3137
        3365
        
        

        现在,我们可以使用许多回归线拟合这些点,一件事是肯定它不是指数的。

        稍微用数字调优后,你可以看到函数4xN^2非常接近它,实际上,这些值完全符合4xN^2 + 1函数。

        让我们尝试在调用次数之上绘制这个函数。

        import matplotlib.pyplot as plt
        
        plt.plot(n_On)
        plt.plot([4*(i**2) + 1 for i in range(1,30)], 'k+')
        plt.xlabel('N')
        plt.ylabel('number of calls')
        plt.show()
        
        
        

        非常合适!

        现在,为什么?在您的递归函数中,您主要有 2 个变量正在改变 i 和 j。由于 i 和 j 仅在 N 范围内变化(由于您的检查 i, j > 0 和 i, j NxN -> N^2)并且您也确实使用了记忆(不访问已经访问过的单元格),所以这里总共有 N^2 种可能性。

        最后,每个案例有 4 次调用。因此,这种复杂性。

        所以,它是O(N^2)

        【讨论】:

        • 非常感谢。我原以为会是N^2,但由于缺乏证据而无法得出结论!
        猜你喜欢
        • 2012-08-14
        • 1970-01-01
        • 2023-02-26
        • 2015-03-31
        • 2022-11-14
        • 1970-01-01
        • 2015-11-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多