zoukankan      html  css  js  c++  java
  • 最长回文字符串

    题目描述:给定一个字符串 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 };
    
    
  • 相关阅读:
    SD卡测试
    测试人员可能会遇到的问题
    HDU 1024 Max Sum Plus Plus
    HDU 1176 免费馅饼
    HDU 1257 最少拦截系统
    HDU 1087 Super Jumping! Jumping! Jumping!
    poj 1328 Radar Installation
    poj 1753 Flip Game
    HDU 1003 Max Sum
    HDU 5592 ZYB's Premutation(BestCoder Round #65 C)
  • 原文地址:https://www.cnblogs.com/zz1314/p/12901450.html
Copyright © 2011-2022 走看看