5.Longest Palindromic Substring
Given a string s, find the longest palindromic substring in s.
Example:
Input: s = "babad"
Output: "bab"
Algorithm:
- Initialize a 2D array dp of size m x n, where m is the length of the input string s and n is the maximum length of a palindromic substring.
- Iterate through the input string s and for each character c, check if it is the same as the previous character c-1. If it is, mark the corresponding cell in dp as true.
- Iterate through the input string s and for each character c, check if it is the same as the next character c+1. If it is, mark the corresponding cell in dp as true.
- Iterate through the 2D array dp and find the longest palindromic substring.
Code:
// 动态规划
func longestPalindrome(s string) string {
// 长度为1 肯定是回文串
if len(s) <= 1 {
return s
}
// start 代表回文串开始下标,end 代表结束下标
var start, maxLen, length = 0, 1, len(s)
// 二维数组dp[i][j] 表示索引 i 到索引 j 是否回文,true 是,否则不是
var dp = make([][]bool, len(s))
// 长度为 1 的肯定是回文, 所有的 dp[i][i] 都是 true
for i := 0; i < length; i++ {
// 初始化数组
dp[i] = make([]bool, length)
dp[i][i] = true
}
// i,j 是回文左右下标,k 是中间回文子串长度
// 回文判断规则:s[i]=s[j] 其中 j = i+中间回文子串长度,由于从0开始遍历,下标需要减1
// 边界情况:
// k长度为2,中间子串长度0也是回文
// 中间子串下标规则 dp[i+1][j-1]
// 由于 k 长度 1 都是回文,从长度 2 开始遍历
for k := 2; k <= length; k++ {
for i := 0; i <= length-k; i++ {
j := i + k - 1
if s[i] == s[j] && (k == 2 || dp[i+1][j-1]) {
dp[i][j] = true
// 更新回文子串长度
if k > maxLen {
start = i
maxLen = k
}
}
}
}
return s[start : start+maxLen]
}
中心扩展法
// 中心扩展
func longestPalindrome1(s string) string {
if len(s) < 2 {
return s
}
// 起始位置、结束位置
start, end := 0, 0
for i := 0; i < len(s); i++ {
// 以一个字符中心扩展
exp1 := expand(s, i, i)
// 以两个字符中心扩展
exp2 := expand(s, i, i+1)
maxLen := max(exp1, exp2)
// 在每次扩展后,我们比较当前回文串的长度和已知的最长回文子串长度,
// 如果大于最长回文子串长度,则更新最长回文子串的起始位置和结束位置。
if maxLen > end-start+1 {
// 起始位置=当前位置i - (maxLen-1)/2
start = i - (maxLen-1)/2
// 结束位置=当前位置i + maxLen/2
end = i + maxLen/2
}
}
return s[start : end+1]
}
func expand(s string, left, right int) int {
for left >= 0 && right < len(s) && s[left] == s[right] {
left--
right++
}
// 因为扩展时左右边界都多扩展了一步
return right - left - 1
}
func max(a, b int) int {
if a > b {
return a
}
return b
}