以下代码的时间复杂度是多少?我知道它有多次递归调用所以它应该是3 ^ n,但每次它初始化长度为n的数组时,后者使用它并且它有点让我感到困惑。如果我们要添加额外的数组来应用memoization,那么时间复杂度应该是多少?以下是Hackerrank Java 1D阵列(硬)任务的解决方案。
public static boolean solve(int n, int m, int[] arr, boolean[] visited, int curr) {
if (curr + m >= n || curr + 1 == n) {
return true;
}
boolean[] newVisited = new boolean[n];
for (int i = 0; i < n; i++) {
newVisited[i] = visited[i];
}
boolean s = false;
if (!visited[curr+1] && arr[curr+1] == 0) {
newVisited[curr+1] = true;
s = solve(n,m,arr,newVisited,curr+1);
}
if (s) {
return true;
}
if (m > 1 && arr[curr+m] == 0 && !visited[curr+m]) {
newVisited[curr+m] = true;
s = solve(n,m,arr,newVisited,curr+m);
}
if (s) {
return true;
}
if (curr > 0 && arr[curr-1] == 0 && !visited[curr-1]) {
newVisited[curr-1] = true;
s = solve(n,m,arr,newVisited,curr-1);
}
return s;
}
答案 0 :(得分:1)
您的实施确实似乎具有指数复杂性。我没有真正考虑过你问题的这一部分。提出最糟糕的情况可能有点乏味。但是,一个“至少非常糟糕”的情况是将n-m
中的第一个arr
元素设置为0,将最后m
个元素设置为1.大量分支就在那里,没有真正利用记忆机制。我猜你的解决方案至少是n/m
中的指数。
这是另一种解决方案。我们可以将问题重新解释为图形问题。让数组中的元素成为定向图形的顶点,并让以下形式之一的每对顶点之间有一条边:(x,x-1)
,(x,x+1)
和(x,x+m)
,如果此边的两端都有值0.在图表中添加一个额外的顶点t
。同时在{n-m+1,n-m+2,...,n}
到t
的每个顶点添加一个值为0的边。因此,我们的图表中只有3n+m
个边。现在,您的问题等同于确定我们刚构建的图中是否存在从顶点0
到t
的路径。这可以通过从顶点0
开始运行深度优先搜索来实现,其具有复杂度O(|E|)
,在我们的示例中为O(n+m)
。
回到你的解决方案,你正在做同样的事情(也许没有意识到)。唯一真正的区别在于您正在将visited
数组复制到newVisited
,因此永远不会真正使用所有的memoization:p所以,只需消除newVisited
,只要你使用visited
正在使用newVisited
并检查会发生什么。