Leetcode 131:分割回文串(最详细的解法!!!)

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回 s 所有可能的分割方案。

示例:

输入: "aab"
输出:
[
  ["aa","b"],
  ["a","a","b"]
]

解题思路

这个问题和前面的 Leetcode 93:复原IP地址(最详细的解法!!!)很类似。首先想到的解法是回溯法。

我们首先判断a是不是回文字符,我们发现是,所以将a加入到list中,接着我们看后面的a,依次下去,当我们第一次遍历完整个字符串的时候,result中就加入了['a','a','b']。接着我们再次遍历,我们发现aa是回文字符串,我们将aa加入到list中,然后我们判断b是一个回文字符,我们将b加入到list中,现在result中就包含了['aa', 'b']。接着我们第三次遍历,我们发现aab不是一个字符串,然而输入的字符大小就是3,这个时候我们输出result

class Solution:
    def _partition(self, s, index, t, result):
        if index == len(s):
            result.append(t.copy())
            return 

        for i in range(index+1, len(s)+1):
            if s[index:i] == s[index:i][::-1]:
                t.append(s[index:i])
                self._partition(s, i, t, result)
                t.pop()
        
    def partition(self, s):
        """
        :type s: str
        :rtype: List[List[str]]
        """
        result = list()
        if not s:
            return result
        
        self._partition(s, 0, list(), result)
        return result

同样的,对于递归可以解决的问题,我们都应该思考是不是可以通过迭代解决。我们看一下该怎么做,我们首先遍历s中的字符,对于每个字符,我们首先将他加入到一个临时的list中。

Leetcode 131:分割回文串(最详细的解法!!!)_第1张图片

当我们遍历到第一个a的时候,我们首先将其加入到list中。

Leetcode 131:分割回文串(最详细的解法!!!)_第2张图片 Leetcode 131:分割回文串(最详细的解法!!!)_第3张图片

当我们遍历到第二个a的时候,我们首先将其加入到list中,接着我们发现'aa'构成回文串,所以我们同时需要将'aa'也加入进来(此时我们放到新的一排)。

Leetcode 131:分割回文串(最详细的解法!!!)_第4张图片 Leetcode 131:分割回文串(最详细的解法!!!)_第5张图片

当我们遍历到b的时候,我们首先将其加入到list中,接着我们就要判断他和之前的元素a是否可以构成回文或者和之前的两个元素['a','a']是否可以构成回文(注意是第一排,不是第二排),我们发现都不行。

class Solution:
    def partition(self, s):
        """
        :type s: str
        :rtype: List[List[str]]
        """
        results = [[]]
        
        for c in s:
            for r in results:
                r.append(c)
                
            tmp = []
            for r in results:
                if len(r) > 1:
                    p = ''.join(r[-2:])
                    if p == p[::-1]:
                        tmp.append(r[:-2] + [p])
                    elif len(r) > 2:
                        p = ''.join(r[-3:])
                        if p == p[::-1]:
                            tmp.append(r[:-3] + [p])
                            
            results.extend(tmp)
        return results

上面的代码中有过多的分支语句,我们希望可以优化一下代码。所以很自然的写出下面的代码

if len(r) > 1:
    p = ''.join(r[-2:])
    if p == p[::-1]:
        tmp.append(r[:-2] + [p])
elif len(r) > 2:
    p = ''.join(r[-3:])
    if p == p[::-1]:
        tmp.append(r[:-3] + [p])

但是这个代码是错的,考虑这样的例子efe。当我们考虑到第三个e的时候,此时我们的list[['e','f']],我们会首先将a加入到其中就变成了[['e','f','e']],接着我们发现'e''f'不可以构成回文,所以我们不可以构成回文,我们的判断就结束了。那能不能这样写?

if len(r) > 1:
    p = ''.join(r[-2:])
    if p == p[::-1]:
        tmp.append(r[:-2] + [p])
if len(r) > 2: # dif
    p = ''.join(r[-3:])
    if p == p[::-1]:
        tmp.append(r[:-3] + [p])

也是错误的,考虑这样的例子aaa。当我们考虑到第三个a的时候,此时我们的list[['a','a'],['aa']],我们会首先将a加入到其中就变成了[['a','a','a'],['aa','a']]。接着我们考虑第一行,我们发现'a''a'可以构成回文,所以我们加入['a', 'aa'],我们发现aaa可以构成回文,所以加入['aaa']。接着我们考虑第二行,我们发现aaa可以构成回文,所以我们加入['aaa']。此时我们发现加入了重复的一项。

一个稍微好一点的解决方案如下

class Solution:
    def partition(self, s):
        """
        :type s: str
        :rtype: List[List[str]]
        """
        if not s: 
            return []

        res = [[]]
        for i, x in enumerate(s):
            tmp = []
            for r in res:
                tmp.append(r+[x])
                if len(r) >= 1 and r[-1] == x: 
                    tmp.append(r[:-1]+[r[-1]+x])
                    
                if len(r) >= 2 and r[-2] == x: 
                    tmp.append(r[:-2]+[r[-2]+r[-1]+x])
                    
            res = tmp
        return res

但是算法思路和前者稍有不同,不过也只是大同小异罢了。

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

你可能感兴趣的:(Problems,leetcode解题指南)