回文分区时间复杂度

Posted

技术标签:

【中文标题】回文分区时间复杂度【英文标题】:Palindrome Partitioning Time Complexity 【发布时间】:2021-07-23 09:38:49 【问题描述】:

我正在解决一个面试练习题:

Partition 使得分区的每个子串都是回文。返回 s 的所有可能的回文分区。

我的解决方案如下,被接受了。

def partition(self, s: str) -> List[List[str]]:
    
    ans = []
    
    def bt(w, curr):
        if not w:
            ans.append(curr)
        else:
            for l in range(1, len(w)+1):
                chunk = w[:l]
                if ''.join(reversed(chunk)) != chunk:
                    continue
                bt(w[l:], curr + [chunk])
    
    bt(s, [])
    return ans

解中给出的时间复杂度为O(N * 2^N)

我明白:

有 2^(N-1) 个可能的分区, 在最坏的情况下,任何分区都会产生回文, 检查回文与输入的大小成线性关系。

但我很难估计在 for 循环中完成的工作量。

任何见解/提示都会有所帮助。结合这一点,我无法写出递归关系..

非常感谢!!

【问题讨论】:

您似乎没有考虑函数成本中的递归调用。 @horcrux 你能详细说明一下吗? 【参考方案1】:

简答

猜测解的指数成本和验证解的多项式成本。因此,总成本是指数函数和多项式函数的乘积。

长答案

在最坏的情况下,continue 语句将永远无法到达,因此每个循环都会有一个递归调用。在这种情况下,如果你有一个n-character-long 单词,你将有nfor 循环,每个循环最多调用n-1for 循环,每个循环最多调用n-2for循环...即,成本为O(n!)

但是,阶乘成本来自对上限的非常粗略的估计,我们可以更精确。

事实上,我们可以注意到当前chunk 的长度在每次递归调用和for 循环的每次迭代中都会减小。 例如,如果原始字符串长度为 4 个字符,则当前 chunk 的长度将为:

3
├─2
| ├─1
| | ├─0
| | 0
| 1
| ├─0
| 0
2
├─1
| ├─0
| 0
1
├─0
0

其中垂直步骤 (|) 表示同栈级循环,而水平步骤 () 表示递归调用。

不难看出,这是O(2^n),确实总步数正好是2^n-1

然后,考虑到每次迭代都必须反转chunk,这显然需要花费O(n)

将两者结合起来,您会得到O(n*2^n)

【讨论】:

以上是关于回文分区时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章

这个回文算法的时空复杂度?

Leetcode链表回文链表(234)

回文链表

查找最长回文子串--Longest Palindromic Substing(java实现时间复杂度O(n))

回文树(模板)

Manacher算法最长子回文串