0005. 最长回文子串 Longest Palindromic Substring
这个问题, 要充分考虑回文字符串的特性:
- 如果回文字符串有奇数个字符, 那就以中间那个字符为分界, 左右两侧完全相同
- 如果回文字符串有偶数个字符, 那中间两个字符相同, 并且它们左右两侧也完全相同
基于这个特性, 可以利用双指针法来找出回文子串, 具体步骤是:
- 先遍历字符串中的每个字符
- 并以它为中心字符 (middle), 利用远离型双指针, 分别向左右两侧扩张, 并且 s[left] == s[right]
- 接下来考虑偶数个字符的情况, 以 (middle, middle + 1) 为中心, 利用远离型双指针, 分别向左右两侧扩张
- 通过这个循环, 就可以找出字符串 s 中的所有回文子串
- 然后保存下来最长的那个子串, 既是最终的结果
代码实现如下:
Rust
#![allow(unused)] fn main() { // 远离型双指针 pub fn longest_palindrome1(s: String) -> String { fn two_sides_equal(s: &str, left: usize, right: usize) -> bool { // 先检查两个索引值的有效性, 再比较它们指向的字符是否相等. right < s.len() && s.as_bytes().get(left) == s.as_bytes().get(right) } let mut longest_palindrome_len = 0; let mut longest_palindrome_start = 0; // 遍历所有字符 for middle in 0..s.len() { // 以 (middle) 为对称点, substring 有奇数个字符 let mut left = middle; let mut right = middle; while two_sides_equal(&s, left, right) { let length = right - left + 1; if longest_palindrome_len < length { longest_palindrome_len = length; longest_palindrome_start = left; } if left == 0 { break; } left -= 1; right += 1; } // 以 (middle, middle+1) 作为对称点, substring 有偶数个字符 left = middle; right = middle + 1; while two_sides_equal(&s, left, right) { let length = right - left + 1; if longest_palindrome_len < length { longest_palindrome_len = length; longest_palindrome_start = left; } if left == 0 { break; } left -= 1; right += 1; } } // 返回结果 s[longest_palindrome_start..longest_palindrome_start + longest_palindrome_len].to_owned() } }
Python
def longestPalindrome(s: str) -> str:
# 跟据回文字符串的特性
def twoSidesEqual(s: str, left: int, right: int) -> bool:
# 先检查两个索引值的有效性, 再比较它们指向的字符是否相等.
if left >= 0 and right < len(s) and s[left] == s[right]:
return True
else:
return False
longest_palindrome_len = 0
longest_palindrome_start = 0
# 遍历所有字符
for middle in range(len(s)):
# 以 (middle) 为对称点, substring 有奇数个字符
left = middle
right = middle
while twoSidesEqual(s, left, right):
length = right - left + 1
if longest_palindrome_len < length:
longest_palindrome_len = length
longest_palindrome_start = left
left -= 1
right += 1
# 以 (middle, middle+1) 作为对称点, substring 有偶数个字符
left = middle
right = middle + 1
while twoSidesEqual(s, left, right):
length = right - left + 1
if longest_palindrome_len < length:
longest_palindrome_len = length
longest_palindrome_start = left
left -= 1
right += 1
# 返回结果
return s[longest_palindrome_start:longest_palindrome_start+longest_palindrome_len]
def main():
s1 = "babad"
out1 = longestPalindrome(s1)
assert(out1 == "bab")
s2 = "cbbd"
out2 = longestPalindrome(s2)
assert(out2 == "bb")
if __name__ == "__main__":
main()