2021-06-06:一个字符串添加最少的字符变成回文串,请返回其中一个结果。

福大大 答案2021-06-06:

动态规划回溯。按照昨天的每日一题求出二维数组dp,然后根据dp回溯。
从dp右上角出发,看dp的左边,下边,左下边。如果dp和左边差值是1,朝左走;如果dp和下边差值是1,朝下走;剩余情况,朝左下走。

代码用golang编写。代码如下:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {

    rand.Seed(time.Now().Unix())
    TOTAL := 1000
    count := 0
    for i := 0; i < TOTAL; i++ {
        s := genRandString()
        ret := getPalindromeString(s)
        isPalindrome := IsPalindromeString(ret)
        if isPalindrome {
            count++
        }
        fmt.Println(s, "", isPalindrome, "", ret)
    }

    fmt.Println("总数:", TOTAL)
    fmt.Println("正确数:", count)

}

func IsPalindromeString(s string) bool {
    if len(s) <= 1 {
        return true
    }
    N := len(s)
    for i := 0; i < N/2; i++ {
        if s[i] != s[N-i-1] {
            return false
        }
    }
    return true
}

func genRandString() string {
    ans := make([]byte, rand.Intn(5)+5)
    for i := 0; i < len(ans); i++ {
        ans[i] = byte('A' + rand.Intn(26))
    }
    return string(ans)
}

func getPalindromeString(s string) string {
    if len(s) == 0 {
        return ""
    }
    dp := getDp(s)
    N := len(s)
    ans := make([]byte, N+dp[0][N-1])
    L := 0
    R := N - 1
    ansL := 0
    ansR := len(ans) - 1
    for {
        if dp[L][R] == 0 {
            break
        }
        if dp[L][R] == dp[L+1][R]+1 {
            ans[ansL] = s[L]
            ans[ansR] = s[L]
            L++
        } else if dp[L][R] == dp[L][R-1]+1 {
            ans[ansL] = s[R]
            ans[ansR] = s[R]
            R--
        } else { //左下
            ans[ansL] = s[L]
            ans[ansR] = s[R]
            L++
            R--
        }
        ansL++
        ansR--
    }

    for L <= R {
        ans[ansL] = s[L]
        ans[ansR] = s[R]
        L++
        R--
        ansL++
        ansR--
    }

    return string(ans)

}

func getDp(s string) [][]int {
    if len(s) == 0 {
        return [][]int{}
    }
    N := len(s)
    dp := make([][]int, N)
    for i := 0; i < N; i++ {
        dp[i] = make([]int, N)
    }
    //对角线以下无效
    //对角线默认全0
    //紧贴对角线的线,首尾相等为0,不等为1
    for i := 0; i < N-1; i++ {
        if s[i] != s[i+1] {
            dp[i][i+1] = 1
        }
    }

    //从下行往上行遍历,从左往右
    for i := N - 3; i >= 0; i-- {
        for j := i + 2; j < N; j++ {
            if s[i] == s[j] {
                //相等看【左下边】
                dp[i][j] = dp[i+1][j-1]
            } else {
                //不等看【左边】和【下边】
                dp[i][j] = getMin(dp[i+1][j], dp[i][j-1]) + 1
            }
        }
    }

    //二维dp表
    return dp
}

func getMin(a int, b int) int {
    if a < b {
        return a
    } else {
        return b
    }
}

执行结果如下:
在这里插入图片描述