找不到最长的回文子串的解决方案之一无法理解

时间:2015-06-10 09:48:19

标签: algorithm palindrome

参考这个article on leetcode,解决最长的回文子串问题是一个常见的错误:

  

反转S并成为S'。找到S和S'之间最长的公共子串,它也必须是最长的回文子串。

例如:

  

S =“abacdfgdcaba”,S'=“abacdgfdcaba”。

     

S和S'之间最长的公共子串是“abacd”。显然,这不是一个有效的回文。

但以下整改我无法理解。任何人都可以通过一步一步的程序/示例来解释它吗?谢谢!

  

为了纠正这个问题,每当我们找到一个最长的公共子串候选者时,我们检查子串的索引是否与反向子串的原始索引相同。

4 个答案:

答案 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();
    }
}

Live demo

它通过了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);
    }
};