参考这个article on leetcode,解决最长的回文子串问题是一个常见的错误:
反转S并成为S'。找到S和S'之间最长的公共子串,它也必须是最长的回文子串。
例如:
S =“abacdfgdcaba”,S'=“abacdgfdcaba”。
S和S'之间最长的公共子串是“abacd”。显然,这不是一个有效的回文。
但以下整改我无法理解。任何人都可以通过一步一步的程序/示例来解释它吗?谢谢!
为了纠正这个问题,每当我们找到一个最长的公共子串候选者时,我们检查子串的索引是否与反向子串的原始索引相同。
答案 0 :(得分:3)
我被困在那里,所以我谷歌到达这里。现在我明白了。让我把作者提到的原始字符串作为一个例子。
S = "caba', S' = "abac", so longest common substring is aba.
句子是“我们检查子串的索引是否与反向子串的原始索引相同。”
1.子串的索引是什么?
"aba" is [1, 2, 3]
2.什么是反转子串的原始指数? 反向子串是“aba”,其原始索引也是[1,2,3]。
所以答案是正确的。
我们正在寻找另一个例子。
S="abacdfgdcaba", S' = "abacdgfdcaba", so longest common substring is "abacd".
同样的过程:
1.子串的索引是什么?
"abacd" is [0, 1, 2, 3, 4].
2.什么是反转子串的原始指数?
反向子字符串为"abacd"
,但其原始索引也为[7, 8, 9, 10, 11]
。
所以这两个"abacd"
不是同一个,答案是不正确的。
我认为这句话有点棘手,我认为作者有点难以理解。
我认为句子应该改为“为了纠正这个问题,每当我们找到最长的公共子串候选者时,我们检查子串是否与反向子串相同”。
答案 1 :(得分:2)
有一些有效的算法可以通过反转原始子串来计算最长的回文子串。例如,以下内容:
1)创建一个广义字符串S1#S2 $,取O(n)
1)构造后缀数组O(n) - >不是微不足道的,但有简单的O(nlogn)和O(nlog ^ 2n)算法
2)构造lcp阵列O(n) - >琐碎的(也有一个普通的O(nlogn))
3)构造RMQ数据结构:O(n)构造和O(1)查询 - >不是微不足道的(有琐碎的O(nlogn)构造和O(logn)查询)
4)迭代原始字符串S1中的每个位置i。在广义字符串中找到S2中的补码位置。找到最长的公共前缀:O(1)
一般而言,必须针对偶数和奇数长度的回文修改所提及的方法。区别在于,在奇数长度的回文中,您只需在选择指数时引入间隙 这产生了问题的O(n)解决方案。
关于文章:
作者提到找到最长的公共子串是不够的,因为具有这种lcp的两个子串可能不是原始字符串中的邻居。
因此,我们希望找到两个字符串A和B,一个属于S1,一个属于S2,因此lcp(A,B)最大,但也是A. rev(B)在原始S1中。
我希望我已经足够清楚。
答案 2 :(得分:1)
万一有人在寻找这个问题的实现,我们使用最长公共子串来找到最长回文子串,这是我的版本。
package leetcodeproblems;
/**
* Created by Nandan Mankad on 23-11-19.
*/
public class LongestPalindromicSubstring {
public static void main(String[] args) {
/*String s = "aacdefcaa";*/
/*String s = "dabcbae";*/
/*String s = "babad";*/
/*String s = "cbbd";*/
/*String s = "cbbc";*/
String s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
System.out.println(longestPalindrome(s));
}
public static String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return s;
}
StringBuilder sb = new StringBuilder(s);
String revString = sb.reverse().toString(); // Reversing the string - to compute LCS.
int dp[][] = new int[s.length() + 1][s.length() + 1];
int maxLength = 0;
int iPos = 0;
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp.length; j++) {
if (s.charAt(i - 1) == revString.charAt(j - 1)) { // Character matches in Original String and Reversed String.
dp[i][j] = dp[i - 1][j - 1] + 1; // Standard Longest Common Substring logic for Original and Reversed String.
int revIdx = i;
int forIdx = j - dp[i][j] + 1;
if (s.length() - revIdx + 1 == forIdx) { // Here we check if the reverse string original idx is same as original string idx.
if (maxLength < dp[i][j]) {
maxLength = dp[i][j];
iPos = i;
}
}
} else {
dp[i][j] = 0;
}
}
}
StringBuilder res = new StringBuilder();
while (maxLength > 0) {
res.append(s.charAt(iPos- 1));
maxLength--;
iPos--;
}
return res.toString();
}
}
它通过了Leetcode上的所有测试用例以解决问题。如果我们反向迭代字符串而不是反向实际字符串,则可能会即兴创作。
时间复杂度:O(N ^ 2) 空间复杂度:O(N ^ 2)
答案 3 :(得分:0)
我只是从leetcode开始,偶然发现了上述文章。
试图实现完全相同的逻辑。是成功的,但效率没有提到的Longest palindromic substring | Dynamic programming
DP解决方案高您只需检查范围是否等于实现算法中的逻辑即可。
这是我实现本文的解决方案。运行时间为 364毫秒,仅比C ++在线提交的21.99%快
class Solution {
public:
string longestPalindrome(string s) {
int max = 0,temp,mr=0;
string revs = s;
reverse(revs.begin(), revs.end());
string soln;
int l = s.size();
if(l==0 || l==1) return s;
int dp[l+1][l+1];
for(int row = 0; row < l; row ++)
for(int col = 0; col < l; col ++){
if(s.at(row) != revs.at(col))
dp[row+1][col+1] = 0;
else{
if(row==0 or col ==0) temp = 1;
else temp = dp[row][col] + 1;
dp[row+1][col+1] = temp;
if(temp > max && row-temp+1 == l-col -1 && l-row -1 == col-temp +1 ){
mr = row;max = temp;
}
}
}
/* for(int row = 0; row < l+1; row ++){
for(int col = 0; col < l+1; col ++){
if(row == 0 && col > 0)
cout << revs.at(col-1) << ", ";
else if(col == 0 && row > 0)
cout << s.at(row-1) << ", ";
else
cout << dp[row][col] << ", ";
}
cout << endl;
}
cout << "\n___________\nmax:" << max <<"\nmr: " << mr << "\n"; */
//return (max>1)?s.substr(mr-max+1,max):s.substr(0,1);
return s.substr(mr-max+1,max);
}
};