LeetCode 3.5 Longest Palindromic Substring

本文深入探讨了寻找最长回文子串的多种算法,包括暴力枚举、记忆化搜索、动规及Manacher’s Algorithm。通过对比它们的时间复杂度和空间复杂度,帮助读者理解每种方法的优缺点,并提供了实际代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3.5 Longest Palindromic Substring

描述

Given a stringS, find the longest palindromic substring inS. You may assume that the maximumlength ofS is 1000, and there exists one unique longest palindromic substring.

page66image12736

3.5 Longest Palindromic Substring61

page67image1008

分析

最长回文子串,非常经典的题。思路一:暴力枚举,以每个元素为中间元素,同时从左右出发,复杂度O(n2)。思路二:记忆化搜索,复杂度O(n2)。设f[i][j]表示[i,j]之间的最长回文子串,递推方程如

下:

  f[i][j] = if (i == j) S[i]
            if (S[i] == S[j] && f[i+1][j-1] == S[i+1][j-1]) S[i][j]
            else max(f[i+1][j-1], f[i][j-1], f[i+1][j])

思路三:动规,复杂度O(n2)。设状态为f(i,j),表示区间[i,j]是否为回文串,则状态转移方

程为


true , i= j

f(i, j) =S[i] = S[j], j =i + 1S[i]=S[j]andf(i+1,j1),j>i+1

思路三:Manachers Algorithm, 复杂度O(n)。详细解释见http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html

备忘录法

// LeetCode, Longest Palindromic Substring//备忘录法,会超时

//时间复杂度O(n^2),空间复杂度O(n^2)typedef string::const_iterator Iterator;

  namespace std {
  template<>
  struct hash<pair<Iterator, Iterator>> {
      size_t operator()(pair<Iterator, Iterator> const& p) const {
          return ((size_t) &(*p.first)) ^ ((size_t) &(*p.second));

}};

}

  class Solution {
  public:
      string longestPalindrome(string const& s) {
          cache.clear();
          return cachedLongestPalindrome(s.begin(), s.end());
      }
  private:
      unordered_map<pair<Iterator, Iterator>, string> cache;
      string longestPalindrome(Iterator first, Iterator last) {
          size_t length = distance(first, last);
          if (length < 2) return string(first, last);
page68image1224
          auto s = cachedLongestPalindrome(next(first), prev(last));
          if (s.length() == length - 2 && *first == *prev(last))
              return string(first, last);
          auto s1 = cachedLongestPalindrome(next(first), last);
          auto s2 = cachedLongestPalindrome(first, prev(last));
          // return max(s, s1, s2)
          if (s.size() > s1.size()) return s.size() > s2.size() ? s : s2;
          else return s1.size() > s2.size() ? s1 : s2;

}

      string cachedLongestPalindrome(Iterator first, Iterator last) {
          auto key = make_pair(first, last);
          auto pos = cache.find(key);
          if (pos != cache.end()) return pos->second;
          else return cache[key] = longestPalindrome(first, last);
      }

};



动规

// LeetCode, Longest Palindromic Substring//动规,时间复杂度O(n^2),空间复杂度O(n^2)class Solution { public:

string longestPalindrome(string s) { const int n = s.size(); bool f[n][n]; fill_n(&f[0][0], n * n, false); // vector会超时 //vector<vector<bool> > f(n, vector<bool>(n, false));size_t max_len = 1, start = 0; //最长回文子串的长度,起点

          for (size_t i = 0; i < s.size(); i++) {
              f[i][i] = true;

for(size_tj=0;j<i;j++){ //[j,i]
f[j][i] = (s[j] == s[i] && (i - j < 2 || f[j + 1][i - 1]));if (f[j][i] && max_len < (i - j + 1)) {

                      max_len = i - j + 1;

start = j;}

}}

          return s.substr(start, max_len);
      }

};

page69image992


Manaers Algorithm

// LeetCode, Longest Palindromic Substring// Manachers Algorithm // 时间复杂度O(n),空间复杂度O(n) class Solution {

  public:
      // Transform S into T.
      // For example, S = "abba", T = "^#a#b#b#a#$".
      // ^ and $ signs are sentinels appended to each end to avoid bounds checking
      string preProcess(string s) {
          int n = s.length();
          if (n == 0) return "^$";
          string ret = "^";
          for (int i = 0; i < n; i++) ret += "#" + s.substr(i, 1);

ret += "#$";

return ret;

}

string longestPalindrome(string s) {
string T = preProcess(s);
const int n = T.length();
// 
T[i]为中心,向左/右扩张的长度,不包含T[i]自己,//因此P[i]是源字符串中回文串的长度

          int P[n];
          int C = 0, R = 0;
          for (int i = 1; i < n - 1; i++) {
              int i_mirror = 2 * C - i; // equals to i' = C - (i-C)
              P[i] = (R > i) ? min(R - i, P[i_mirror]) : 0;
              // Attempt to expand palindrome centered at i
              while (T[i + 1 + P[i]] == T[i - 1 - P[i]])

P[i]++;

              // If palindrome centered at i expand past R,
              // adjust center based on expanded palindrome.
              if (i + P[i] > R) {

C = i;

R = i + P[i];}

}

          // Find the maximum element in P.
          int max_len = 0;
          int center_index = 0;
          for (int i = 1; i < n - 1; i++) {
              if (P[i] > max_len) {
                  max_len = P[i];
                  center_index = i;
page70image1232

}}

    return s.substr((center_index - 1 - max_len) / 2, max_len);
}

}; 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值