给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
示例 1:
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
示例 2:
输入:s = "a"
输出:[["a"]]
提示:
- 1 <= s.length <= 16
- s 仅由小写英文字母组成
解题:
// 这种字符串是真的难
官方解答:
1.回溯 + 动态规划预处理
func partition(s string) (ans [][]string) {
n := len(s)
f := make([][]bool, n)
for i := range f {
f[i] = make([]bool, n)
for j := range f[i] {
f[i][j] = true
}
}
for i := n - 1; i >= 0; i-- {
for j := i + 1; j < n; j++ {
f[i][j] = s[i] == s[j] && f[i+1][j-1]
}
}
var splits []string
var dfs func(int)
dfs = func(i int) {
if i == n {
ans = append(ans, append([]string(nil), splits...))
return
}
for j := i; j < n; j++ {
if f[i][j] {
splits = append(splits, s[i:j+1])
dfs(j + 1)
splits = splits[:len(splits)-1]
}
}
}
dfs(0)
return
}
2.回溯 + 记忆化搜索
func partition(s string) (ans [][]string) {
n := len(s)
f := make([][]int8, n)
for i := range f {
f[i] = make([]int8, n)
}
// 0 表示尚未搜索,1 表示是回文串,-1 表示不是回文串
var isPalindrome func(i, j int) int8
isPalindrome = func(i, j int) int8 {
if i >= j {
return 1
}
if f[i][j] != 0 {
return f[i][j]
}
f[i][j] = -1
if s[i] == s[j] {
f[i][j] = isPalindrome(i+1, j-1)
}
return f[i][j]
}
var splits []string
var dfs func(int)
dfs = func(i int) {
if i == n {
ans = append(ans, append([]string(nil), splits...))
return
}
for j := i; j < n; j++ {
if isPalindrome(i, j) > 0 {
splits = append(splits, s[i:j+1])
dfs(j + 1)
splits = splits[:len(splits)-1]
}
}
}
dfs(0)
return
}
提交了官方的答案,执行用时和内存消耗明显比之前的题目多太多了,怪不得我脑袋不够用了。。