回文划分 II 的时间和 Space 复杂度

Time and Space complexity of Palindrome Partitioning II

所以我正在解决这个 LeetCode 问题 - https://leetcode.com/problems/palindrome-partitioning-ii/ 并提出了以下最朴素的暴力递归解决方案。现在,我知道如何记住这个解决方案,并通过动态规划尽可能地做到最好。但是为了找到进一步解决方案的 time/space 复杂性,我想看看这个解决方案有多糟糕,我在多个地方查找但未能找到具体的 T/S 复杂性回答。

def minCut(s: str) -> int:
    def is_palindrome(start, end):
        while start < end:
            if not s[start] == s[end]:
                return False
            start += 1
            end -= 1
        return True

    def dfs_helper(start, end):
        if start >= end:
            return 0

        if is_palindrome(start, end):
            return 0
        curr_min = inf
        
        # this is the meat of the solution and what is the time complexity of this
        for x in range(start, end):
            curr_min = min(curr_min, 1 + dfs_helper(start, x) + dfs_helper(x + 1, end))
        return curr_min

    return dfs_helper(0, len(s) - 1)

让我们来看看最坏的情况,即回文检查不允许我们提前出局。

为了写出递归关系,假设n = end - start,这样n就是要处理的序列的长度。我假设索引数组访问是常数时间。

is_palindrome 将在 O(end - start) = O(n) 步中检查回文。

dfs_helper 对于长度为 n 的子序列,调用 is_palindrome 一次,然后进行 2n 次长度从 0 到 n - 1 的递归调用,每次调用两次,加上通常的常量开销为了简单起见,我将省略。

所以,我们有

T(0) = 1
T(n) = O(n) + 2 * (sum of T(x) for x=0 to n-1)
# and for simplicity, I will just use
T(n) = n + 2 * (sum of T(x) for x=0 to n-1)

这个模式已经 has to be at least exponential。我们可以看看接下来的几个步骤:

T(1)  =   3 = 1 + 2 *  1  =  1 + 2 * (T(0))
T(2)  =  10 = 2 + 2 *  4  =  2 + 2 * (T(0) + T(1))
T(3)  =  31 = 3 + 2 * 14  =  3 + 2 * (T(0) + T(1) + T(2))
T(4)  =  94 = 4 + 2 * 45  =  4 + 2 * (T(0) + T(1) + T(2) + T(3))

看起来好像增长速度大约与 3^n 一样快。我们还可以证明对于 n > 2:

T(n) = n + 2 * (sum of T(x) for x=0 to n-1)
T(n) = n + 2 * (T(0) + T(1) + ... + T(n-1))
T(n) = n + 2 * (T(0) + T(1) + ... + T(n-2)) + 2 * T(n-1)
T(n) = 1 +  n-1 + 2 * (T(0) + T(1) + ... + T(n-2))  +  2 * T(n-1)

# with
T(n-1) = n-1 + 2 * (sum of T(x) for x=0 to n-2)
T(n-1) = n-1 + 2 * (T(0) + T(1) + ... + T(n-2))

# we can substitute:
T(n) = 1 + T(n-1) + 2 * T(n-1)
T(n) = 1 + 3 * T(n-1)

所以,如果我没记错的话,渐近时间复杂度应该在θ(3^n),或者,允许我开个玩笑,even worse than O(no)

对于 Space 复杂性:您的函数没有显式分配任何内存。因此,只有递归的恒定开销(假设 python 没有优化它)。这里重要的一点是两个递归步骤会一个接一个发生,这样我们就得到了递归:

S(0) = 1
S(n) = 1 + S(n-1)

这给了我们 θ(n) 的 space 复杂度。