算法题之最大回文子串
题目描述
对于一个字符串,请设计一个高效算法,计算其中最长回文子串的长度。
给定字符串A以及它的长度n,请返回最长回文子串的长度。
测试样例:
"abc1234321ab",12
返回:7
1. 普通轮询(运行时间80ms):
class Palindrome { public: bool isHuiWen(string A, int n){ int k = n / 2; for (int i = 0; i < k; ++i) { if (A.at(i) != A.at(n - 1 - i)) return false; } return true; } int getLongestPalindrome(string A, int n) { // write code here int maxlen = 0; for (int i = 0; i< n; i++){ for (int j = i + 1; j <= n; j++){ //两层循环遍历出所有的子串,并且逐一判断是否是回文 if (isHuiWen(A.substr(i, j-i), j - i)){ if (j - i>maxlen) maxlen = j - i; } } } return maxlen; } };
附:Leetcode上一个不错的递归解法:
#include <iostream> using namespace std; int lps(char* str, int i, int j) { //只有一个元素,长度为1 if (i == j) return 1; //只计算序列str[i...j] if (i > j) return 0; //如果首尾相同 if (str[i] == str[j]) return lps(str, i+1, j-1) + 2; //如果首尾不同 return max(lps(str, i, j-1), lps(str, i+1, j)); } int main() { char* str = "AABACACBA"; cout << lps(str, 0, strlen(str)-1) << endl; return 0; }
2. 动态规划(运行时间40ms):
import java.util.*; public class Palindrome { public int getLongestPalindrome(String A, int n) { // write code here int[][] dp = new int[n][n]; int max = 1; for (int i = 0; i < n; ++i) { dp[i][i] = 1; } char[] a = A.toCharArray(); for (int len = 2; len <= n; ++len) { for (int i = 0; i <= n - len; ++i) { int j = i + len - 1; if (len == 2 && a[i] == a[j]) { dp[i][j] = len; max = 2; continue; } if (a[i] == a[j] && dp[i + 1][j - 1] != 0) { dp[i][j] = len; max = len; } } } return max; } }
另一种解法:
//动态规划求解最长回文子序列,时间复杂度为O(n^2) int lpsDp(char *str, int n) { int dp[n+1][n+1], tmp; memset(dp, 0, sizeof(dp)); for (int i = 0; i < n; ++i) dp[i][i] = 1; for (int i = 1; i < n; ++i) { tmp = 0; //考虑所有连续的长度为i+1的子串,str[j....j+i] for (int j = 0; j + i < n; j++) { //如果首尾相同 if (str[j] == str[j + i]) tmp = dp[j + 1][j + i - 1] + 2; //如果首尾不同 else tmp = max(dp[j + 1][j + i], dp[j][j + i - 1]); dp[j][j + i] = tmp; } } return dp[0][n - 1]; //返回字符串str[0...n-1]的最长回文子序列长度 }
3. Manacher解法(时间复杂度O(n),运行时间<1ms):
class Palindrome { public: int getLongestPalindrome(string A, int n) { int max = 1; for (int i = 0; i < n; i++) { int num = 1; for (int left = i - 1, right = i + 1; left >= 0 && right < n; left--, right++) { if (A[left] == A[right]) { num += 2; } else { break; } } if (max < num) { max = num; } } for (int i = 0; i < n; i++) { int num = 0; for (int left = i, right = i + 1; left >= 0 && right < n; left--, right++) { if (A[left] == A[right]) { num += 2; } else { break; } } if (max < num) { max = num; } } return max; } };