Leetcode5--->最长回文子串

题目:给定一个字符串s,找出s中的最长回文子串;

暴力法,DP法, 中心扩展法,manacher算法

解法一:暴力法

遍历字符串S的每一个子串,去判断这个子串是不是回文,是回文的话看看长度是不是比最大的长度maxlength大。遍历每一个子串的方法要O(n^2),判断每一个子串是不是回文的时间复杂度是O(n),所以暴利方法的总时间复杂度是O(n^3)。

 1 public static String findLongestPalindrome(String s){
 2         int len = s.length(); // 字符串长度
 3         int maxlength = 0;  // 最长回文字符串长度
 4         int start = 0; // 回文开始的地方
 5         for(int i = 0; i < len; i++){
 6             for(int j = i + 1; j < len; j++){
 7                 int index1 = 0;
 8                 int index2 = 0;
 9                 // 对每个子串都从两边开始向中间遍历
10                 for(index1 = i, index2 = j; index1 < index2; index1 ++, index2--){
11                     if(s.charAt(index1) != s.charAt(index2))
12                         break;
13                 }
14                 // 若index1=index2,表示串是类似于abcba这种类型;若大于,则是abccba这种类型
15                 if(index1 >= index2 && j - i > maxlength){
16                     maxlength = j - i + 1;
17                     start = i;
18                 }
19             }
20
21         }
22         if(maxlength > 0)
23             return s.substring(start, start + maxlength);
24         return null;
25
26     }

解法二: 动态规划

回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么P[i+1,j-1]也是回文字符串。这样最长回文子串就能分解成一系列子问题了。这样需要额外的空间O(N^2),算法复杂度也是O(N^2)。

首先定义状态方程和转移方程:

P[i,j]=false:表示子串[i,j]不是回文串。P[i,j]=true:表示子串[i,j]是回文串。

P[i,i]=true:当且仅当P[i+1,j-1] = true && (s[i]==s[j])

否则p[i,j] =false;

 1 public static String findLongestPalindrome1(String s){
 2         int len = s.length();
 3         int start = 0;
 4         int maxlength = 0;
 5         boolean p[][] = new boolean[s.length()][s.length()];
 6         // 子串长度为1和为2的初始化
 7         for(int i = 0; i < len; i++){
 8             p[i][i] = true;
 9             if(i < len - 1 && s.charAt(i) == s.charAt(i + 1)){
10                 p[i][i + 1] = true;
11                 start = i;
12                 maxlength = 2;
13             }
14         }
15         // 使用上述结果可以dp出子串长度为3~len -1的子串
16         for(int strlen = 3; strlen < len; strlen ++){
17             for(int i = 0; i <=len - strlen; i++){
18                 int j = i + strlen - 1; // 子串结束的位置
19                 if(p[i + 1][j - 1] && s.charAt(i) == s.charAt(j)){
20                     p[i][j] = true;
21                     maxlength = strlen;
22                     start = i;
23                 }
24             }
25         }
26         if(maxlength > 0)
27             return s.substring(start, start + maxlength);
28         return null;
29     }

解法三:中心扩展法

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。

但是要考虑两种情况:

1、像aba,这样长度为奇数。

2、想abba,这样长度为偶数。

 1 public static String findLongestPalindrome2(String s){
 2         int len = s.length();
 3         int maxlength = 0;
 4         int start = 0;
 5         // 类似于aba这种情况,以i为中心向两边扩展
 6         for(int i = 0; i < len; i++){
 7             int j = i - 1;
 8             int k = i + 1;
 9             while(j >= 0 && k < len && s.charAt(j) == s.charAt(k)){
10                 if(k - j + 1 > maxlength){
11                     maxlength = k - j + 1;
12                     start = j;
13                 }
14                 j --;
15                 k ++;
16             }
17         }
18         // 类似于abba这种情况,以i,i+1为中心向两边扩展
19         for(int i = 0; i < len; i++){
20             int j = i;
21             int k = i + 1;
22             while(j >= 0 && k <len && s.charAt(j) == s.charAt(k)){
23                 if(k - j + 1 > maxlength){
24                     maxlength = k - j + 1;
25                     start = j;
26                 }
27                 j --;
28                 k ++;
29             }
30         }
31         if(maxlength > 0)
32             return s.substring(start, start + maxlength);
33         return null;
34     }

解法四:Manacher算法

Manacher法只能解决例如aba这样长度为奇数的回文串,对于abba这样的不能解决,于是就在里面添加特殊字符。我是添加了“#”,使abba变为a#b#b#a。这个算法就是利用已有回文串的对称性来计算的,具体算法复杂度为O(N)

 1 public static String findLongestPalindrome3(String s) {
 2         if(s == null || s.length() < 1)
 3             return "";
 4         String str = dealWithS(s);  // 处理一下s,即将给字符串s的中间加上特殊字符,这样无论对于奇数字符还是偶数字符可以做同样的处理
 5         int[] res = new int[str.length()];
 6         int R = 0; // 当前所能扩展的半径
 7         int C = 0; // C位置的半径为R
 8         int maxC= 0; // 最长的半径的位置
 9         res[0] = 0;
10         for(int i = 1; i < str.length(); i++)
11         {
12             int j = 2 * C - i;  // i点的对称点
13             if(j >= 0 && res[j] < R - i)  // 对称点存在且对称点的回文半径在C的回文中
14             {
15                 res[i] = res[j];
16             }
17             else  // 否则,需要根据i点一点一点的计算
18             {
19                 int k = 1;
20                 while(R + k < str.length() && 2 * i - R - k >= 0)
21                 {
22                     if(str.charAt(R + k) == str.charAt(2 * i - R - k))
23                         k ++;
24                     else
25                         break;
26                 }
27                 res[i] = R -i + k - 1;
28                 if(res[i] + i > R)
29                 {
30                     R = res[i] + i;
31                     C = i;
32                 }
33             }
34
35             maxC = res[maxC] > res[i] ? maxC : i;  // maxC保存的是回文半径最大的那个点的位置
36         }
37         String subStr = str.substring(maxC - res[maxC], maxC + res[maxC] + 1);
38         StringBuffer sb = new StringBuffer();
39         for(int i = 0; i < subStr.length(); i++)
40         {
41             if(subStr.charAt(i) != ‘#‘)
42                 sb.append(subStr.charAt(i));
43         }
44         return sb.toString();
45     }
46     public static String dealWithS(String s)  // 将原字符串进行处理
47     {
48         StringBuffer sb = new StringBuffer();
49         sb.append("#");
50         for(int i = 0; i < s.length (); i++)
51         {
52             sb.append(s.charAt(i));
53             sb.append("#");
54         }
55         return sb.toString();
56     }
时间: 2024-09-29 22:19:59

Leetcode5--->最长回文子串的相关文章

leetcode-5 最长回文子串(动态规划)

题目要求: * 给定字符串,求解最长回文子串 * 字符串最长为1000 * 存在独一无二的最长回文字符串 求解思路: * 回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串, * 那么P[i+1,j-1]也是回文字符串.这样最长回文子串就能分解成一系列子问题了. * 这样需要额外的空间O(N^2),算法复杂度也是O(N^2). * 首先定义状态方程和转移方程: * P[i,j]=0表示子串[i,j]不是回文串.P[i,j]=1表示子串[i,j]是回文串. * P

《算法竞赛入门经典》3.3最长回文子串

1 //例题3-4 2 /* 3 * 输入一个字符串,求出其中最长的回文子串.子串的含义是:在原串中连续出现的字符串片段. 4 *回文的含义是:正看着和倒看着相同,如abba和yyxyy.在判断时,应该忽略所有标点符号和空格 5 *且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符).输入字符长度不超过5000 6 *且占据单独的一行.应该输出最长回文串,如果有多个,输出起始位置最靠左的. 7 *样例输入:Confuciuss say:Madam,I'm Adam. 8 *样例

Manacher算法----最长回文子串

题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些的子串,那么对子串的回文判断其实是不需要的.同时,奇数和偶数长度还要分别考虑. Manacher算法可以解决上述问题,并在O(n)时间复杂度内求出结果.下面我们来看一下Manacher算法. 首先,为了处理奇偶的问题,在每个字符的两边都插入一个特殊的符号,这样所有的奇数或偶数长度都转换为奇数长度.比

hihocoder1302 最长回文子串

hihocoder1302 最长回文子串 先贴代码 所有的上面的提示已经交代的好清楚了…… #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <map> #include <queue> #include <sta

[hiho 01]最长回文子串、Manacher算法

题目描述 - 基础方法:枚举子串,判断是否为回文串. - 改进:枚举中间位置,向两侧拓展. - 再改进:利用以前的信息,使得不用每个新位置都从长度1开始拓展. - 优化:将字符串预处理为奇数长度以避免考虑条件分支. - 再优化:开头加入特殊字符避免考虑边界. Manacher 算法: id 是中心点,mx 是其边界.P[i] 表示以 i 为中心的最长回文子串的折半长度. 只要 i < mx, 以 i 为中心的回文子串就可以不必从长度1开始找,而从min{P[j], mx - i}开始(其中j为i

[C++]LeetCode: 99 Longest Palindromic Substring (最长回文子串)

题目:Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 思路:题目要求的s的一个最长回文子串.暴力解决办法就是枚举所有的子串,再对每个子串进行回文判断.进行剪枝,我们考虑可以使用动态规划来避免重复的判

[译]最长回文子串(Longest Palindromic Substring) Part II

[译+改]最长回文子串(Longest Palindromic Substring) Part II 问题:给定字符串S,求S中的最长回文子串. 在上一篇,我们给出了4种算法,其中包括一个O(N2)时间O(1)空间的算法(中心检测法),已经很不错了.本篇将讨论一个O(N)时间O(N)空间的算法,即著名的Manacher算法,并详细说明其时间复杂度为何是O(N). 提示 +BIT祝威+悄悄在此留下版了个权的信息说: 先想想有什么办法能改进中心检测法. 考虑一下最坏的情况.★ 最坏的情况就是各个回文

URAL 1297 后缀数组:求最长回文子串

思路:这题下午搞了然后一直WA,后面就看了Discuss,里面有个数组:ABCDEFDCBA,这个我输出ABCD,所以错了. 然后才知道自己写的后缀数组对这个回文子串有bug,然后就不知道怎么改了. 然后看题解,里面都是用RMQ先预处理任意两个后缀的最长公共前缀,因为不太知道这个,所以又看了一下午,嘛嘛-- 然后理解RMQ和后缀一起用的时候才发现其实这里不用RMQ也可以,只要特殊处理一下上面这个没过的例子就行了,哈哈--机智-- 不过那个国家集训队论文里面正解是用RMQ做的,自己还得会和RMQ一

最长回文子串(转自:hihoCoder)

#1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:"小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?" 小Ho奇怪的问道:"什么叫做最长回文子串呢?" 小Hi回答道:"一个字符串中连续的一

URAL-1297 Palindrome (最长回文子串)

Palindrome Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Description The “U.S. Robots” HQ has just received a rather alarming anonymous letter. It states that the agent from the competing «Robots Unlimited» has infiltrat