1312. 让字符串成为回文串的最少插入次数

61 阅读1分钟

题目:
给你一个字符串 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
}