Longest Palindromic Substring问题

Longest Palindromic Substring问题

1.题目描述

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.//aba也是有效的答案

Example:
Input: "cbbd"
Output: "bb"

给定一个字符串s,找到当中的最长回文子串。你可能需要假设s的最大长度是1000。

这里解释一下回文串的定义:
“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。

题目中的回文子串就是满足回文串性质的最长子串。

2.解题思路

看到这道题的时候,第一个想法就是暴力解法,扫描以每个字符串为中心的回文串,在其中找到最长的那个回文子串,就可以的出结果,这中思路没有什么技巧,比较好想,代码也比较好写,但是边界问题还有一些细节需要注意:

  1. 当字符串为空或者只有一个的情况。
  2. 遇到第一个字符和最后一个字符的时候怎么处理。
  3. aba和abba情况的区分。
    这是最简单也是最笨的解决这种问题的思路,在discuss里面有更好的解决办法,能把复杂度降到O(n)的神奇算法,我根据算法实现了代码,但是超时了,好无奈。这里给出一个博客,总结了这道题的各种解法:
    博客地址,还有一篇专门介绍这种方法的博客

3.代码

  1. class Solution
  2.  
  3. public String test(String s,int l,int r)
  4. int n = s.length(); 
  5. while(l>=0 && r<=n-1 && s.charAt(l)==s.charAt(r)) { 
  6. //限定l和r的范围,并比较是否相等,相等就对范围进行扩张。 
  7. l--; 
  8. r++; 

  9. return s.substring(l+1, r); 
  10. //这里就要仔细 考虑边界情况以及当自己和自己比较的时候 
  11. //l--,但是可能存在下个不满足条件,而substring函数是不包括r这个边界的 

  12. public String longestPalindrome(String s)
  13. int slen = s.length(); 
  14. if(slen==0
  15. return null;//若字符串为空 
  16. //int[] p = new int[slen]; 
  17. String longString = "";//新建一个空的字符串 
  18. for(int i=0;i<slen;i++) { 
  19. String p1= test(s,i,i+1);//这种情况是对于abba这种中间有重复的情况,是偶数 
  20. String p2 = test(s,i,i);//这种情况对应于aba这种情况,是奇数 
  21. if(p1.length()>p2.length()) {//获得当前的最大回文串 
  22. longString = longString.length()>p1.length()? longString:p1; 

  23. else 
  24. longString = longString.length()>p2.length()? longString:p2; 

  25. return longString; 

  26.  

下面是leetcode上排名前几的代码,它的基本思路也是查找以每个字符为中心的回文串,但是它优化了碰到重复字符时的情况:

  1. class Solution
  2. private int max_length; 
  3. private int start; 
  4.  
  5. public String longestPalindrome(String s)
  6. if(s.length() < 2
  7. return s; 
  8. for(int i = 0; i < s.length();) { 
  9. i = extendPalindrome2sides(s, i); 

  10. return s.substring(start, start + max_length); 

  11.  
  12. private int extendPalindrome2sides(String s, int anchor)
  13. //Skip duplicate characters. 
  14. int j = anchor, k = anchor; 
  15. while(k < s.length() - 1 && s.charAt(k) == s.charAt(k + 1)) k++; 
  16. //这句代码跳过了重复字符,也就是处理了偶数的那种情况 
  17. //当是奇数的时候,不会进入循环 
  18. int next_i = k + 1;//计算出下一个需要进行回文计算的字符 
  19.  
  20. while(j >= 0 && k < s.length() && s.charAt(j) == s.charAt(k)) { 
  21. j--; 
  22. k++; 

  23. int cur_leng = (--k) - (++j) + 1
  24. //这个--k和++j,理解起来有点模糊,但是写的很优雅 
  25. //还是想到边界情况:当最后一个不满足的时候,但是index已经定位到它们, 
  26. //这就需要把左边还原 
  27. if(cur_leng > max_length) { 
  28. start = j; 
  29. max_length = cur_leng; 

  30.  
  31. return next_i; 


传说中的马拉车算法:

  1. public static String longestPalindrome1(String s)
  2. if(s.length()==0
  3. return null
  4. String tmp = "$#"
  5. for(int i= 0;i<s.length();i++) { 
  6. tmp+=s.charAt(i); 
  7. tmp+="#"

  8. tmp+="^"
  9. int [] p=new int[tmp.length()]; 
  10.  
  11. int c = 0,r=0,len=0,cen=0
  12. for(int i=1;i<tmp.length()-1;i++) { 
  13. p[i] = r>i? Math.min(p[2*c-i],r-i):1
  14. while(tmp.charAt(i-p[i])==tmp.charAt(i+p[i])) 
  15. p[i]++; 
  16. if(r<i+p[i]) { 
  17. r=i+p[i]; 
  18. c=i; 

  19. if(p[i]>len) { 
  20. len=p[i]; 
  21. cen = i; 


  22. int pos =(cen-len)/2
  23. return s.substring(pos, pos+len-1); 
  24.  

原文地址:https://www.cnblogs.com/chailinbo/p/7445547.html