给定一个字符串 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
中。
当我们遍历到第一个a
的时候,我们首先将其加入到list
中。
当我们遍历到第二个a
的时候,我们首先将其加入到list
中,接着我们发现'aa'
构成回文串,所以我们同时需要将'aa'
也加入进来(此时我们放到新的一排)。
当我们遍历到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']
,我们发现a
,a
和a
可以构成回文,所以加入['aaa']
。接着我们考虑第二行,我们发现a
和aa
可以构成回文,所以我们加入['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
如有问题,希望大家指出!!!