LeetCode 5: Longest Palindromic Substring
Description:
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: "babad" Output: "bab" Note: "aba" is also a valid answer.
Example 2:
Input: "cbbd" Output: "bb"
描述:
给定字符串s,查找s的最长回文子串。
假设字符串s的最大长度为1000.
示例1:
输入: “babad” 输出: "bab" 注意:“aba”也是有效的答案
示例2:
输入:“cbbd” 输出: “bb”
方法一:暴力破解
首先,明确回文的概念。“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。
遍历字符串s的每一个子串,并判断该子字符串是否为回文。
class Solution { public: string longestPalindrome(string s) { int len = s.length(); string str; int maxLen = 0; if(len == 0) return s; for(int i = 0; i < len; i++) { for(int j = i + 1; j <= len; j++) { int len = palindromeLen(s, i, j); if(len >= maxLen) { maxLen = len; str = s.substr(i, j - i); } } } return str; } int palindromeLen(string str, int start, int end) { int s = start; int e = end - 1; while(s <= e) { if(str[s++] != str[e--]) return 0; } return end - start; } };
该方法的时间复杂度为O(n3),空间复杂度为O(n)。运行时间为1796ms。
方法2:动态规划
首先,我们考虑如何减少重复比较的次数。以“ababa”为例,如果我们已经知道“bab”为回文,那么“ababa”也是回文,因为“bab”首端和末端的字符相等,均为字符‘a’。
显而易见地,
P(i,j) = true, 如果Si,...,Sj为回文串,反之,P(i,j) = false
因此,P(i,j) = (P(i+1, j-1) and Si == Sj)。
并且,P(i,i) = true, 当Si == Si+1时P(i, i+1) = true。
class Solution { public: string longestPalindrome(string s) { int len = s.length(); if(len == 0 || len == 1) return s; bool p[len][len]; for(int i = 0; i < len; i++) { for(int j = 0; j < len; j++) { p[i][j] = false; } } int maxLen = 0; string ans; for(int l = 0; l < len; l++) { for(int i = 0; i < len - l; i++) { int j = i + l; if(s[i] == s[j] && (l < 2 || p[i+1][j-1])) { p[i][j] = true; if(l + 1 > maxLen) { maxLen = l + 1; ans = s.substr(i, l+1); } } } } return ans; } };
本方法的时间复杂度为O(n2),空间复杂度为O(n),运行时间为108ms。
方法三:中心扩展法
中心扩展法的核心思想是选定一个中心,并不断向两端扩展来判断是否是回文字符串。
对于长度为n的字符串,共有2n-1个中心:首先,可以选定每个字符为中心,并不断向两端扩展,共有n中选法,此时选定的是“aba”型的回文字符串;其次,可以选定每对字符中间位置为中心,共有n-1中选法,此时选定的是“abba”型回文字符串。
class Solution { public: string longestPalindrome(string s) { int len = s.length(); if(len == 0 || len == 1) return s; string ans; int maxLen = 0; for(int i = 0; i < len - 1; i++) { int len1 = isPalindrome(s, i, i); if(len1 > maxLen) { maxLen = len1; ans = s.substr(i - len1 / 2, len1); } int len2 = isPalindrome(s, i, i + 1); if(len2 > maxLen) { maxLen = len2; ans = s.substr(i + 1- len2 / 2, len2); } } return ans; } int isPalindrome(string s, int start, int end) { int len = s.length(); while(start >= 0 && end < len) { if(s[start] == s[end]) { start--; end++; } else { break; } } return end - start - 1; } };
本方法的时间复杂度为O(n2),空间复杂度为O(n),运行时间为12ms。