如何通过memoization计算递归的时间复杂度?

时间:2015-11-20 21:50:56

标签: algorithm recursion big-o complexity-theory memoization

以下代码的时间复杂度是多少?我知道它有多次递归调用所以它应该是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;
}

1 个答案:

答案 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个边。现在,您的问题等同于确定我们刚构建的图中是否存在从顶点0t的路径。这可以通过从顶点0开始运行深度优先搜索来实现,其具有复杂度O(|E|),在我们的示例中为O(n+m)

回到你的解决方案,你正在做同样的事情(也许没有意识到)。唯一真正的区别在于您正在将visited数组复制到newVisited,因此永远不会真正使用所有的memoization:p所以,只需消除newVisited,只要你使用visited正在使用newVisited并检查会发生什么。