最长回文字符串

题目描述:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

解析:最长回文字符串就是正过来和反过来一样的字符串,比如上海自来水来自海上,小明到操场操到天明。。

方法一:从最暴力的方法入手,直接遍历所有的子字符串

 1 class Solution {
 2 public:
 3     string longestPalindrome(string s) {
 4         //暴力解法
 5         int length = s.length();
 6         int max = 0;
 7         string res = "";
 8         for(int i = 0; i < length; i++){
 9             for(int j = i + 1; j <= length; j++){
10                 string tmp = string(s, i, j - i);
11                 //cout << tmp << endl;
12                 if(isPalindrome(tmp) && tmp.length() > max){
13                     //cout << tmp << endl;
14                     max = tmp.length();
15                     res = tmp;
16                 }
17             }
18         }
19         return res;
20         
21     }
22 
23     bool isPalindrome(string s){
24         for(int i = 0; i < s.length() / 2; i++){
25             if(s[i] != s[s.length() - i - 1]){
26                 return false;
27             }
28         }
29         return true;
30     }
31 };

分析:遍历子字符串需要n(n - 1)/2,复杂度为O(n^2),每次判断是否为回文字符串的复杂度为O(n),所以,此算法复杂度为O(n^3);

方法二:通过字符串翻转,然后找到最长公共字串,再判断是否是回文字串

 1 class Solution {
 2 public:
 3     string longestPalindrome(string s) {
 4         string s_resvere = s;
 5         reverse(s_resvere.begin(), s_resvere.end());  // 翻转字符串
 6         return findlongestSubStr(s, s_resvere, s.length());
 7     }
 8 
 9     string findlongestSubStr(string s1, string s2, int length){
10         bool check = 0;
11         string res;
12         for(int step = length; step > 0; step--){
13             for(int i = 0; i + step - 1 < length; i++){
14                 string tmp = string(s1, i, step);  //定义一个临时变量,从i下标开始,往后加step个字符串
15                 if(s2.find(tmp) != -1){
16                     string rtmp = tmp;
17                     reverse(rtmp.begin(), rtmp.end());
18                     if(rtmp == tmp){
19                         res = tmp;
20                         check = 1;
21                         break;
22                     }
23                 }
24             }
25             if(check) break;
26         }
27         return res;
28     }
29 };

分析:此算法的时间复杂度仍然为o(n^3);

 方法三:动态规划,通过动态规划存放之前比较的结果,从而将时间复杂度缩减至O(n^2)

 1 class Solution {
 2 public:
 3     string longestPalindrome(string s) {
 4         int length = s.length();
 5         if(length <= 1) return s;
 6         int max = 1;  //代表最大回文串长度
 7         int start = 0; //代表回文串的起始下标
 8         int dp[1000][1000] = {0}; // 定义一个二维数组,初始化为0,dp[i][j]=1代表从 从i 到 j闭区间内为回文串
 9         for(int i = 0; i < length; i++){   // 进行初始化,如果为dp[i][i]一定为回文串,置为1,同样,两个连续的相同的字符也能组成一个回文串
10             dp[i][i] = 1;
11             if(i < length - 1 && s[i] == s[i + 1]) {
12                 start = i;
13                 max = 2;
14                 dp[i][i + 1] = 1;
15             }
16         }
17         for(int size = 3; size <= length; size++){ //之前从2 判断过了, 所以从3开始进行判断
18             int right;
19             for(int left = 0; left + size - 1< length; left++){
20                 right = left + size - 1;
21                 if(s[left] == s[right] && dp[left + 1][right - 1] == 1){ // 如果左边等于右边,而且中间还是回文串,那么这个[left,right]一定是回文串
22                     dp[left][right] = 1;
23                     max = size;
24                     start = left;
25                 }
26             }
27         }
28         return s.substr(start, max);
29     }
30 };

 方法四:中心扩展算法,通过中心扩展,减少相应的迭代步骤,降低时间复杂度。具体实现:一个回文串的中心可能是一个字符,也可能是两个字符,如果以一个字符为中心,有n个中心,以两个字符为中心,就有n-1个中心,所以一共有2n-1个中心;

 1 class Solution {
 2 public:  
 3     string longestPalindrome(string s) {
 4         int length = s.length();
 5         if(length <= 1) return s;
 6         int max_res = 1;
 7         int start = 0;
 8         for(int i = 0; i < length; i++){
 9             int max1 = maxLength(s, i, i);
10             int max2 = maxLength(s, i, i + 1);
11             if(max_res < max(max1, max2)){
12                 max_res = max(max1, max2);
13                 start = i - (max_res - 1) / 2;
14                 //cout << "max = "<< max_res << " " <<" start = " << start << " i = " << i <<endl;
15             }
16         }
17         return s.substr(start, max_res);
18     }
19 
20 private:
21     int maxLength(string s, int left, int right){  
22         while(left >= 0 && right < s.length() && s[left] == s[right]) {
23             left--;
24             right++;
25         }
26         return right - left - 1;
27     }
28 };

原文地址:https://www.cnblogs.com/zz1314/p/12901450.html