Medium!

题目描述:

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

示例:

  1. 输入: "babad"
  2.  
  3. 输出: "bab"
  4.  
  5. 注意: "aba"也是有效答案

示例:

  1. 输入: "cbbd"
  2.  
  3. 输出: "bb"

回文串概念:

“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。

回文算法描述:

1、初始化标志flag=true;
2、输入字符串str,并获取其长度len;
3、定义并初始化游标i=0,j=len-1,分别指向字符串开头和末尾;
4、比较字符str[i]和str[j],若i==j,转至7,否则往下执行5;
5、若str[i]和str[j]相等,则游标i加1,游标j减1后转至4,否则往下执行6;
6、令标志位flag=flase,结束比较,str不是回文串,算法结束。
7、若str[i]和str[j]相等,结束比较,flag=true,str为回文串,算法结束
  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4.  
  5. int main()
  6. {
  7. string str;
  8. int i,j,l;
  9. int flag = ;
  10.  
  11. while (cin >> str)
  12. {
  13. l = str.length();
  14. for (i = ,j = l-; i <= j; i++,j--)
  15. {
  16. if (str[i] != str[j])
  17. {
  18. flag = ;
  19. }
  20. }
  21. if (flag) cout << "YES" << endl;
  22. else cout << "NO" << endl;
  23. flag = true;
  24. }
  25.  
  26. return ;
  27. }

解题思路:

LeetCode中关于回文串的题共有五道,除了这道,其他的四道为Palindrome Number 验证回文数字Validate Palindrome 验证回文字符串Palindrome Partitioning 拆分回文串Palindrome Partitioning II 拆分回文串之二,我们知道传统的验证回文串的方法就是两个两个的对称验证是否相等,那么对于找回文字串的问题,就要以每一个字符为中心,像两边扩散来寻找回文串,这个算法的时间复杂度是O(n*n),可以通过OJ,就是要注意奇偶情况,由于回文串的长度可奇可偶,比如"bob"是奇数形式的回文,"noon"就是偶数形式的回文,两种形式的回文都要搜索。这道题让我们求最长回文子串。

C++参考答案一:

  1. // Time complexity O(n*n)
  2. class Solution {
  3. public:
  4. string longestPalindrome(string s) {
  5. int startIdx = , left = , right = , len = ;
  6. for (int i = ; i < s.size() - ; ++i) {
  7. if (s[i] == s[i + ]) {
  8. left = i;
  9. right = i + ;
  10. searchPalindrome(s, left, right, startIdx, len);
  11. }
  12. left = right = i;
  13. searchPalindrome(s, left, right, startIdx, len);
  14. }
  15. if (len == ) len = s.size();
  16. return s.substr(startIdx, len);
  17. }
  18. void searchPalindrome(string s, int left, int right, int &startIdx, int &len) {
  19. int step = ;
  20. while ((left - step) >= && (right + step) < s.size()) {
  21. if (s[left - step] != s[right + step]) break;
  22. ++step;
  23. }
  24. int wide = right - left + * step - ;
  25. if (len < wide) {
  26. len = wide;
  27. startIdx = left - step + ;
  28. }
  29. }
  30. };

此题还可以用动态规划Dynamic Programming来解,与Palindrome Partitioning II 拆分回文串之二的解法很类似,我们维护一个二维数组dp,其中dp[i][j]表示字符串区间[i, j]是否为回文串,当i = j时,只有一个字符,肯定是回文串,如果i = j + 1,说明是相邻字符,此时需要判断s[i]是否等于s[j],如果i和j不相邻,即i - j >= 2时,除了判断s[i]和s[j]相等之外,dp[j + 1][i - 1]若为真,就是回文串,通过以上分析,可以写出递推式如下:

dp[i, j] = 1                                               if i == j

= s[i] == s[j]                                if j = i + 1

= s[i] == s[j] && dp[i + 1][j - 1]    if j > i + 1

这里有个有趣的现象,就是如果我把下面的代码中的二维数组由int改为vector<vector<int> >后,就会超时,这说明int型的二维数组访问执行速度完爆std的vector,所以,以后尽还是可能用最原始的数据类型吧。

C++参考答案二:

  1. // DP
  2. class Solution {
  3. public:
  4. string longestPalindrome(string s) {
  5. int dp[s.size()][s.size()] = {}, left = , right = , len = ;
  6. for (int i = ; i < s.size(); ++i) {
  7. for (int j = ; j < i; ++j) {
  8. dp[j][i] = (s[i] == s[j] && (i - j < || dp[j + ][i - ]));
  9. if (dp[j][i] && len < i - j + ) {
  10. len = i - j + ;
  11. left = j;
  12. right = i;
  13. }
  14. }
  15. dp[i][i] = ;
  16. }
  17. return s.substr(left, right - left + );
  18. }
  19. };

最后要提的就是大名鼎鼎的马拉车算法Manacher's Algorithm,这个算法的神奇之处在于将时间复杂度提升到了O(n)这种逆天的地步,而算法本身也设计的很巧妙,很值得我们掌握,参见博客:http://www.cnblogs.com/grandyang/p/4475985.html,代码实现如下:

C++参考答案三:

  1. class Solution {
  2. public:
  3. string longestPalindrome(string s) {
  4. string t ="$#";
  5. for (int i = ; i < s.size(); ++i) {
  6. t += s[i];
  7. t += '#';
  8. }
  9. int p[t.size()] = {}, id = , mx = , resId = , resMx = ;
  10. for (int i = ; i < t.size(); ++i) {
  11. p[i] = mx > i ? min(p[ * id - i], mx - i) : ;
  12. while (t[i + p[i]] == t[i - p[i]]) ++p[i];
  13. if (mx < i + p[i]) {
  14. mx = i + p[i];
  15. id = i;
  16. }
  17. if (resMx < p[i]) {
  18. resMx = p[i];
  19. resId = i;
  20. }
  21. }
  22. return s.substr((resId - resMx) / , resMx - );
  23. }
  24. };

官方解答:

摘要:

这篇文章是为中级读者而写的。它介绍了回文,动态规划以及字符串处理。请确保你理解什么是回文。回文是一个正读和反读都相同的字符串。

解决方案:

方法一:最长公共子串

常见错误

有些人会忍不住提出一个快速的解决方案,不幸的是,这个解决方案有缺陷(但是可以很容易地纠正):

  1. 反转 S,使之变成 S'。找到 S 和 S​′之间最长的公共子串,这也必然是最长的回文子串。

算法:

我们可以看到,当 SS 的其他部分中存在非回文子串的反向副本时,最长公共子串法就会失败。为了纠正这一点,每当我们找到最长的公共子串的候选项时,都需要检查子串的索引是否与反向子串的原始索引相同。如果相同,那么我们尝试更新目前为止找到的最长回文子串;如果不是,我们就跳过这个候选项并继续寻找下一个候选。

这给我们提供了一个复杂度为 O(n^2)O(n​2​​) 动态规划解法,它将占用 O(n^2)O(n​2​​) 的空间(可以改进为使用 O(n)O(n) 的空间)。请访问https://en.wikipedia.org/wiki/Longest_common_substring_problem阅读更多关于最长公共子串的内容。

方法二:暴力法

方法三:动态规划

方法四:中心扩展算法

Java代码:

  1. public String longestPalindrome(String s) {
  2. int start = 0, end = 0;
  3. for (int i = 0; i < s.length(); i++) {
  4. int len1 = expandAroundCenter(s, i, i);
  5. int len2 = expandAroundCenter(s, i, i + 1);
  6. int len = Math.max(len1, len2);
  7. if (len > end - start) {
  8. start = i - (len - 1) / 2;
  9. end = i + len / 2;
  10. }
  11. }
  12. return s.substring(start, end + 1);
  13. }
  14.  
  15. private int expandAroundCenter(String s, int left, int right) {
  16. int L = left, R = right;
  17. while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
  18. L--;
  19. R++;
  20. }
  21. return R - L - 1;
  22. }

方法五:Manacher算法

还有一个复杂度为 O(n) 的Manacher算法,你可以在该网站:https://articles.leetcode.com/longest-palindromic-substring-part-ii/找到详尽的解释。然而,这是一个非同寻常的算法,在45分钟的编码时间内提出这个算法将会是一个不折不扣的挑战。但是,请继续阅读并理解它,我保证这将是非常有趣的。

LeetCode(5):最长回文子串的更多相关文章

  1. LeetCode:最长回文子串【5】

    LeetCode:最长回文子串[5] 题目描述 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为1000. 示例 1: 输入: "babad" 输出: ...

  2. 【LeetCode】最长回文子串【动态规划或中心扩展】

    给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad"输出: "bab"注意: " ...

  3. Java实现 LeetCode 5 最长回文子串

    5. 最长回文子串 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab&quo ...

  4. [LeetCode] 5. 最长回文子串 ☆☆☆(最长子串、动态规划)

    最长回文子串 (动态规划法.中心扩展算法) https://leetcode-cn.com/problems/longest-palindromic-substring/solution/xiang- ...

  5. 【LeetCode】最长回文子串-中心扩展法

    [问题]给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 : 输入: "babad" 输出: "bab" 注意: ...

  6. leetcode python最长回文子串

    回文的意思是正着念和倒着念一样,如:上海自来水来自海上,雾锁山头山锁雾,天连水尾水连天 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: & ...

  7. [LeetCode] 5. 最长回文子串

    题目链接:https://leetcode-cn.com/problems/longest-palindromic-substring/ 题目描述: 给定一个字符串 s,找到 s 中最长的回文子串.你 ...

  8. LeetCode 05 最长回文子串

    题目 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab" 注意: ...

  9. 【LeetCode】最长回文子串-动态规划法

    [问题]给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 : 输入: "babad" 输出: "bab" 注意: ...

  10. [leetCode]5. 最长回文子串(DP)

    题目 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 题解 dp.先初始化长度为1和长度为2的串.再依次算长度为3,4,5.... 当找到回文串时,若长度比当 ...

随机推荐

  1. 聊一聊docker存储驱动

    目录 镜像的分层特性 容器读写层的工作原理 写时复制 用时配置 Docker存储驱动 AUFS OverlayFS Devicemapper 常用存储驱动对比 AUFS VS OverlayFS Ov ...

  2. CISCO知识扫盲

    cisco知识扫盲 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.vlan简介 1.什么是VLAN 简称虚拟局域网.至于英语怎么写自行百度吧. VLAN的优势: 1>.广 ...

  3. JavaEE学习总结(十三)—JavaWeb、JSP、Servlet与DVD管理系统

    一.JSP基础知识 1.0.创建数据库与表 /* Navicat MySQL Data Transfer Source Server : 127.0.0.1 Source Server Version ...

  4. javascript 模拟京东关闭广告栏

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. The string "--" is not permitted within comments【转】

    ibatis中SAXParseException异常:The string "--" is not permitted within comments 这个异常是说sqlmap里面 ...

  6. FZU - 1989 AntiAC

     Problem 1989 AntiAC Accept: 93    Submit: 444Time Limit: 4000 mSec    Memory Limit : 32768 KB  Prob ...

  7. Forth 语言概要 - Forth: An underview

    Forth 语言概要 - Forth: An underview 原作者 Peter Knaggs 原文标题< Forth: An underview > 译者: 未知 译文链接: htt ...

  8. css3让图文不能复制

    -webkit-user-select: none; -ms-user-select: none; -moz-user-select: none; -khtml-user-select: none; ...

  9. vue 裁剪图片,插件Cropper的使用

    全局安装    npm install cropperjs 如果想本项目安装,方便移植:   import Cropper from 'cropperjs'   --save    这样的话,本地 p ...

  10. springboot(六)SpringBoot问题汇总

    SpringBoot2.0整合Mybatis,取datetime数据类型字段出来时,发现少了8小时. 过程:mysql中注册时间查询出来结果是正确的,只是java程序运行出来后显示少了8小时.经前辈指 ...