题目:
给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。
请你返回让 s 成为回文串的 最少操作次数 。
「回文串」是正读和反读都相同的字符串。
算法:
方法一:暴力
TLE,时间复杂度2^500
func minInsertions(s string) int {
var dfs func(left, right int) int
dfs = func(left, right int) int {
if left >= right {
return 0
}
if s[left] == s[right] {
return dfs(left + 1, right - 1)
}
return min(dfs(left + 1, right), dfs(left, right - 1)) + 1
}
return dfs(0, len(s) - 1)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
方法二:暴力+记忆化
方法一进行了太多重复的计算,那么我们把结果缓存起来,减少重复计算。
AC!
func minInsertions(s string) int {
mem := make(map[string]int)
var dfs func(left, right int) int
dfs = func(left, right int) int {
if left >= right {
return 0
}
if cnt, ok := mem[s[left:right + 1]]; ok {
return cnt
}
if s[left] == s[right] {
return dfs(left + 1, right - 1)
}
cnt := min(dfs(left + 1, right), dfs(left, right - 1)) + 1
mem[s[left:right + 1]] = cnt
return cnt
}
return dfs(0, len(s) - 1)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
方法三:动态规划
结果 = len(s) - 最长回文子序列长度
func minInsertions(s string) int {
n := len(s)
dp := make([][]int, n)
// s[i] == s[j] dp[i][j] = dp[i+1][j-1] + 2
// s[i] != s[j] = max(dp[i+1][j], dp[i][j-1])
for i := range dp {
dp[i] = make([]int, n)
dp[i][i] = 1
}
for i := n - 1; i >= 0; i -- {
for j := i + 1 ; j < n; j ++ {
if s[i] == s[j] {
dp[i][j] = dp[i+1][j-1] + 2
} else {
dp[i][j] = max(dp[i+1][j], dp[i][j-1])
}
}
}
return len(s) - dp[0][n - 1]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}