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 } }
执行结果如下: