让我们首先采用数据分析方法。我们可以尝试用较小的 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 值初始化了数组,因此我们不满足基本情况 arr[i][j] == 1,因此程序将在最坏的情况下运行。
在 29 之后,我们得到了最大的递归深度,所以我们只选择了 1-29 作为我们的 N。
绘制每个 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)。