memoized递归函数的运行时分析

时间:2018-03-20 17:14:48

标签: algorithm big-o dynamic-programming

下面的代码计算s1是否可以减少到t,如果是这样,有多少种方式。 假设s1的长度为n,t的长度为m。下面代码的最坏情况运行时是O(n ^ m)而没有memoization。假设我们可以记住s1的子问题,即子串重复。运行时间为O(m * n)。因为我们需要为每个n重复m次。这个推理是否正确?

static int distinctSeq(String s1, String t) {
    if (s1.length() == t.length()) {
        if (s1.equals(t))
            return 1;
        else
            return 0;
    }
    int count = 0;
    for (int i = 0; i < s1.length(); i++) {
        String ss = s1.substring(0, i)+ s1.substring(i + 1);
        count += distinctSeqRec(ss, t);
    }
    return count;
}

1 个答案:

答案 0 :(得分:0)

正如@meowgoesthedog已经提到的,您的初始解决方案的时间复杂度为O(n!/m!)

  • 如果您的s1长度为nn > m,那么您可以通过从原始字符串中排除一个符号来进入n个不同的状态。
  • 您将继续这样做,直到您的字符串长度为m。使用给定算法从m获得n长度的方式为n*(n-1)*(n-2)*...*(m+1),这实际上是n!/m!
  • 对于通过从长度为m的初始字符串中排除符号而形成的每个长度为n的字符串,您必须比较来自s1t的字符串,这将需要m次操作(字符串的长度),因此上一步的复杂度应乘以m,但考虑到你在big-O中有阶乘,另一个*m获胜&# 39;改变渐近复杂度。

现在关于memoization。如果添加memoization,则算法将仅转换为尚未访问的状态,这意味着该任务将计算s1的唯一子串的数量。为简单起见,我们将考虑s1的所有符号都不同。长度为x的状态数是从n-x中删除不同s1符号的方式的数量,无视订单。实际上是binomial coefficient - C(n,x) = n!/((n-x)! * x!)

算法将在nm之间转换所有长度,因此整体时间复杂度为Sum(k=m...n, C(n,k)) = n!/((n-1)!*1!) + n!/((n-2)!*2! + ... + n!/((n-k)!*k!)。考虑到我们正在计算渐近复杂度,我们感兴趣的是该和的最大成员,即k尽可能接近n/2的成员。如果m小于n/2,则总和中会出现C(n, n/2),否则C(n,m)是其中最大的元素,因此带有记忆的算法的复杂性为{ {1}}。