`
vvaaiinn
  • 浏览: 20986 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

LeetCode:Longest Palindromic Substring 最长回文子串

 
阅读更多

忽然找到一位关于此题详细介绍的大牛文章。

转载之,以后常回顾一下。

http://www.cnblogs.com/tenosdoit/p/3675788.html

表示没学过动态规划,闲下来时候研究研究。

算法4挺别出心裁,值得学习!


题目链接

Given a stringS, find the longest palindromic substring inS. You may assume that the maximum length ofSis 1000, and there exists one unique longest palindromic substring.

求字符串的最长回文子串

算法1:暴力解法,枚举所有子串,对每个子串判断是否为回文,复杂度为O(n^3)


算法2:删除暴力解法中有很多重复的判断。很容易想到动态规划,时间复杂度O(n^2),空间O(n^2),动态规划方程如下:

  • dp[i][j] 表示子串s[i…j]是否是回文
  • 初始化:dp[i][i] = true (0 <= i <= n-1); dp[i][i-1] = true (1 <= i <= n-1); 其余的初始化为false
  • dp[i][j] = (s[i] == s[j] && dp[i+1][j-1] == true)

在动态规划中保存最长回文的长度及起点即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
classSolution {
public:
string longestPalindrome(string s) {
constintlen = s.size();
if(len <= 1)returns;
booldp[len][len];//dp[i][j]表示s[i..j]是否是回文
memset(dp, 0, sizeof(dp));
intresLeft = 0, resRight = 0;
dp[0][0] = true;
for(inti = 1; i < len; i++)
{
dp[i][i] = true;
dp[i][i-1] = true;//这个初始化容易忽略,当k=2时要用到
}
for(intk = 2; k <= len; k++)//枚举子串长度
for(inti = 0; i <= len-k; i++)//枚举子串起始位置
{
if(s[i] == s[i+k-1] && dp[i+1][i+k-2])
{
dp[i][i+k-1] = true;
if(resRight-resLeft+1 < k)
{
resLeft = i;
resRight = i+k-1;
}
}
}
returns.substr(resLeft, resRight-resLeft+1);
}
};

算法3:以某个元素为中心,分别计算偶数长度的回文最大长度和奇数长度的回文最大长度。时间复杂度O(n^2),空间O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
classSolution {
public:
string longestPalindrome(string s) {
constintlen = s.size();
if(len <= 1)returns;
intstart, maxLen = 0;
for(inti = 1; i < len; i++)
{
//寻找以i-1,i为中点偶数长度的回文
intlow = i-1, high = i;
while(low >= 0 && high < len && s[low] == s[high])
{
low--;
high++;
}
if(high - low - 1 > maxLen)
{
maxLen = high - low -1;
start = low + 1;
}
//寻找以i为中心的奇数长度的回文
low = i- 1; high = i + 1;
while(low >= 0 && high < len && s[low] == s[high])
{
low--;
high++;
}
if(high - low - 1 > maxLen)
{
maxLen = high - low -1;
start = low + 1;
}
}
returns.substr(start, maxLen);
}
};

算法4:Manacher算法,时间复杂度O(n), 空间复杂度O(n)

该算法首先对字符串进行预处理,在字符串的每个字符前后都加入一个特殊符号,比如字符串 abcd 处理成 #a#b#c#d#,为了避免处理越界,在字符串首尾加上不同的两个特殊字符(c类型的字符串尾部不用加,因为自带‘\0’),这样预处理后最终变成$#a#b#c#d#^,经过这样处理后有个好处是原来的偶数长度和奇数长度的回文在处理后的字符串中都是奇数长度。假设处理后的字符串为s本文地址

对于已经预处理好的字符串我们用数组p[i]来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),以字符串“12212321”为例,p数组如下

s: $ # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 # ^
p: 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1


可以看出,P[i]-1正好是原字符串中回文串的总长度,如果p数组已知,遍历p数组找到最大的p[i]就可以求出最长回文的长度,也可以求出回文的位置

下面给出求p[]数组的方法:

设id是当前求得的最长回文子串中心的位置,mx为当前最长回文子串的右边界(回文子串不包括该右边界),即mx = id + p[id]。记j = 2*id – i ,即 j 是 i 关于 id 的对称点。

1、 当i < mx 时,如下图。此时可以得出一个非常神奇的结论p[i] >= min(p[2*id - i], mx - i),下面我们来解释这个结论

image

如何根据p[j]来求p[i]呢,又要分成两种情况

(1.1)当mx – i > p[j], 这时候以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于 i 和 j 对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以 P[i] 至少等于 p[j], 后面的再继续匹配。如下图

注:这里其实p[i]一定等于p[j],后面不用再匹配了。因为如果p[i]后面还可以继续匹配,根据对称性,p[j]也可以继续扩展了

image

(1.2)当mx – i <= p[j], 以S[j]为中心的回文子串不完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] 至少等于 mx - i,至于mx之后的部分是否对称,就只能老老实实去匹配了。

注:如果mx – i < p[j] ,这时p[i]一定等于mx - i, 因为如果p[i]在mx之后还可以继续匹配,根据对称性,mx之后匹配的点(包括mx)一定会出现在my的前面,这说明p[id]也可以继续扩展了

image

2、当i >= mx, 无法对p[i]做更多的假设,只能p[i] = 1,然后再去匹配

算法复杂度分析:根据斜体字部分的注释,只有当mx-i = p[j]时 以及 i > mx时才要扩展比较,而mx也是在不断扩展的,总体而言每个元素比较次数是n的线性关系,所以时间复杂度为O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
classSolution {
public:
string longestPalindrome(string s) {
constintlen = s.size();
if(len <= 1)returns;
//Manncher算法 ,o(n)
string str = preProcess(s);
intn = str.size(), id = 0, mx = 0;
vector<int>p(n, 0);
for(inti = 1; i < n-1; i++)
{
p[i] = mx > i ? min(p[2*id-i], mx-i) : 1;
//if(mx <= i || (mx > i && p[2*id-i] == mx - i)) //根据正文斜体部分的注释,这里可要可不要
while(str[i+p[i]] == str[i-p[i]])p[i]++;
if(i + p[i] > mx)
{
mx = i + p[i];
id = i;
}
}
//遍历p,寻找最大回文长度
intmaxLen = 0, index = 0;
for(inti = 1; i < n-1; i++)
if(p[i] > maxLen)
{
maxLen = p[i];
index = i;
}
returns.substr((index - maxLen)/2, maxLen-1);
}
//预处理字符串,abc预处理后变成$#a#b#c#^
string preProcess(conststring &s)
{
intn = s.size();
string res;
res.push_back('$');//把$放到字符串头部
res.push_back('#');//以#作为原来字符串中每个字符的间隔
for(inti = 0; i < n; i++)
{
res.push_back(s[i]);
res.push_back('#');
}
res.push_back('^');//以^作为字符串的结尾
returnres;
}
};

算法5:可以用后缀数组来解,在源字符串后面加一个特殊字符,然后把源字符串的反转串连接到源字符串后面,那么问题就变成了求这个新字符串的某两个后缀的最长公共前缀,该问题是典型的后缀数组应用,可以参考here,关于后缀数组请关注我的后续博客

参考资料:

Longest Palindromic Substring Part II

Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串

Longest Palindromic Substring | Set 2


分享到:
评论

相关推荐

    LeetCode5 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. Java AC 版本

    leetcode答案-Longest-Palindromic-Substring:最长回文子串

    Longest-Palindromic-Substring(最长回文子串) 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 Sample 1 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 Sample 2 输入...

    最大公共字符串leetcode-longest-palindromic-substring:查找字符串中最长的回文子串

    最长回文子串 给定一个字符串 s,找出 s 中最长的回文子串。 您可以假设 s 的最大长度为 1000。 Example 1: Input: "babad" Output: "bab" Note: "aba" is also a valid answer. Example 2: Input: "cbbd" Output: ...

    leetcode中文版-LeetCode:LeetcodeC++/Java

    最长回文子串 string,dp 8 String to Integer(atoi) 字符串转整数 string 13 Roman to Integer 罗马数字转整数 number,string 14 Longest Common Prefix 最长公共前缀 string 16 3Sum Closest 最接近的三数之和 two ...

    leetcode卡-LeetCode:LeetCode题解

    最长回文子串,Manacher算法 0010 RegularExpressionMatching :star: :star: :star: 正则表达式匹配,dp 0012 Integer to Roman :star: 数组 0013 Roman to Integer :star: 哈希表 0014 Longest Common Prefix :star...

    最大公共字符串leetcode-longest-palindromic-substring:给定一个字符串s,找出s中最长的回文子串。你可以假

    最长回文子串 给定一个字符串 s,找出 s 中最长的回文子串。 您可以假设 s 的最大长度为 1000。 示例 1: Input: "babad" Output: "bab" Note: "aba" is also a valid answer. 示例 2: Input: "cbbd" Output: "bb" ...

    leetcode分类-leetcode:leetcode问题的代码

    leetcode 分类leetcode 问题分类 leetcode代码仓库,我的解题思路写在我的博客里: leetcode 代码库,我博客上的解题思路: mkdir 列表: 大批 #1:Two Sum #4:Median of Two Sorted Arrays 地图 #1:Two Sum #3:...

    javalruleetcode-Leetcode:力码解决方案

    java lru leetcode Leetcode-Java Use Java to solve Leetcode&JianZhiOffer problems. ...(最长回文子串) Medium Dynamic Programming 7 Reverse Integer (整数反转) Easy Math 8 String to Integer (ato

    leetcode跳跃-LeCode:乐科

    最长回文子串 6. ZigZag Conversion Z字型变换 7. Reverse Integer 整数反转 8. String to Integer (atoi) 字符串转换整数 (atoi) 9. Palindrome Number 回文数 10. Regular Expression Matching 正则表达式匹配 11....

    颜色分类leetcode-leetcode-[removed]我对Leetcode问题的解决方案

    最长回文子串 7 Reverse Integer 整数反转 9 Palindrome Number 回文数 11 Container With Most Water 盛最多水的容器 13 Roman to Integer 罗马数字转整数 14 Longest Common Prefix 最长公共前缀 20 Valid ...

    lrucacheleetcode-leetcode-1:leetcode-1

    最长回文子串,补符号,记忆 6. ZigZag Conversion 观察规律 7. Reverse Integer 翻转整数 8. String to Integer 解析字符串 9. Palindrome Number 回文数字 10. Regular Expression Matching 动态规划,列出转换...

    leetcode双人赛-LeetCode:力扣笔记

    leetcode双人赛LeetCode 编号 题目 难度 题型 备注 Two Sum 简单 Add Two Numbers 中等 链结串列 重要 Longest Substring Without Repeating Characters 中等 字串 重要 Median of Two Sorted Arrays 困难 数学 ...

    leetcode跳跃-leetcode:leetcode一天一次

    无重复字符的最长子串:3. Longest Substring Without Repeating Characters - 最小跳跃步数问题 - 动态规划 + 循环策略优化:45. Jump Game II - 二叉树 前序遍历判断二叉树:98. Validate Binary Search Tree - 二...

    leetcode题库-LeetCode:力码

    最长回文子串 Longest Palindromic Substring.cpp 7 整数反转 Reverse Integer.cpp 9 回文数 Palindrome Number.cpp 12 整数转罗马数字 Integer to Roman.cpp 13 罗马数字转整数 Roman to Integer.cpp 15 三数之和 3...

    javalruleetcode-LeetCode::lollipop:个人LeetCode习题解答仓库-多语言

    Palindromic Substring 8 String to Integer 11 Container with Most Water 14 Longest Common Prefix 15 Three Sum 16 Three Sum Closest 20 Valid Parentheses 26 Remove Duplicates from Sorted Array 48 Rotate ...

    leetcode2sum-Problems:编程问题的回购

    leetcode 2sum # Programming-Problems This will have many problems from all over the web, As of writing this readme there is Haskell 99: 28 finished + Huffman Coding LeetCode: LC1: 2Sum [Easy] LC2: Add...

    网格最短leetcodePython-LeetCode:力码

    https://leetcode.com/problems/longest-palindromic-substring/solution/) 解决方案 日期 最长公共子串 6/24 蛮力 6/24 动态规划 8/14 围绕中心展开 8/12 92.反向链表II 解决方案 日期 Head-&gt;Rev-&gt;End 7/5 46.排列 ...

    leetcode知乎-leetcode:leetcode解决方案

    leetcode 知乎 此项目介绍 此项目旨在是为leetcode里面的习题提供解析(数据结构相关知识),锻炼了自己,同时也给别人带来了方便。 网站习题链接: ** 作者知乎链接**: 关于习题 所有习题和解析都写在一个文件里,...

    lrucacheleetcode-leetcode:leetcode

    lru缓存leetcode leetcode 1. Two Sum 2. Add Two Numbers 3. Longest Substring Without Repeating Characters 4. Median of Two Sorted Arrays 5. Longest Palindromic Substring 7. Reverse Integer 9. ...

    leetcode信封-LeetCode:LeetCode解题

    leetcode信封 LeetCode LeetCode解题 源码目录 //main下为源码,test下为单元测试 │ src │ ├─main │ └─java │ └─com │ └─algorithm │ GeneratorParenthesis.java //22. Generate Parentheses | ...

Global site tag (gtag.js) - Google Analytics