如何有效地确定给定字符串中最长的单个字符回文?

Posted

技术标签:

【中文标题】如何有效地确定给定字符串中最长的单个字符回文?【英文标题】:How do I efficiently determine the longest individual character palindrome in a given string? 【发布时间】:2011-11-20 18:52:50 【问题描述】:

给定一个包含字符 [A-Z] 的长度为 N 的字符串,我如何确定单个字符的最长回文?

我会用一个例子来说明这一点:

给定字符串:JOHNOLSON 在分析字符串时,我们发现我们有一个带有字符 O 的回文,使得字符串看起来像 JOHN OLSONO 的回文长度为 7,基本上看起来像 O--O--O强>。另外,请注意有一个带有 N 的回文,但它的长度仅为 6。

另一个例子, 给定字符串:ABCJOHNOLSON 给出与上面相同的结果,长度为 7 的 O 的回文看起来像 O--O --O

然而,对于给定的字符串ABCJOHNOLSONDA,最长的单个字符回文长度为14,字符A看起来像A------------A

其他简单的例子包括:

ABA --> A-A(长度为3)

ABAXYZ --> A-A(长度为3)

ABAXYZA --> A---A(长度为 5),而不是长度为 7,因为 A-A---A 不是 A 的回文。

请特别注意最后一个示例,因为它说明了问题的细微差别之一。

【问题讨论】:

对于您要查找的内容,必须有一个比“回文”更好的术语,因为您的大多数示例都不是回文。 考虑一个示例字符串ABCDAEEALMNA,当考虑A时看起来像A---A--A---A,这是一个大小为12的回文(当你忽略其余字符的唯一性时) ,但考虑字符串ABCDAEEALMNOA,其中整个字符串不再是回文,而是一个小得多的子字符串成为最长的回文,即末尾长度为5的A---A 我了解您感兴趣的pattern,它只是不符合术语回文的字典定义。我想知道您正在寻找的是否有正则表达式解决方案。 @BlastFurnace 我明白你在说什么。你会建议用不同的方式来思考这个问题吗?它以回文的形式出现在我面前,所以我不确定它还能被描述为什么。 【参考方案1】:

您可以在线性时间内完成,它在here 中使用代码示例进行了描述。

【讨论】:

【参考方案2】:

这是我想出来的,我不知道它的效率如何。

对于字母表中的每个字母, 查找此字母的第一个和最后一个匹配项。 虽然子字符串不是该字母的回文(易于检查), 找到两边的下一个字母,这样每个可能的组合都是 检查。取最长的一个并存放它。 取最长的一个。

【讨论】:

当您说在两边找到下一个字母时,您的意思是您当前正在搜索的字符的下一个实例吗?这对于某些字符串会失败,例如“ABAAAACAA” @JordanBentley:不,我的意思是(例如)尝试 0,7 然后 0,6 然后 0,4 然后 0,3 然后 0,2 然后 0,0 然后 2,7 然后 2, 6 然后 2,4 然后 2,3 然后 2,2 然后 3,7 然后 3,6 然后......你明白了:) 但是如果在某些条件下找到回文,你可以打破,立即说。 啊,这更有意义。如果我理解正确,那会起作用,但最坏情况的复杂性将是 O(n!) @JordanBentley:是的,我认为它可能不是那么好。哦,好吧,这是另一种选择:)【参考方案3】:

绝对不是最优的。假设输入字符串都是小写的。

using System;
using System.Collections.Generic;

public class LongestPalindrome

    public int longest(string s)
    
        Dictionary<char, List<int>> indices = 
            new Dictionary<char, List<int>>();

        // find all indices for each letter
        for (int i = 0; i < s.Length; i++)
        
            char c = s[i];
            if (!indices.ContainsKey(c)) 
                    indices.Add(c, new List<int>());
            indices[c].Add(i);
        

        int max = Int32.MinValue;

        for (int i = (int)'a'; i <= (int)'z'; i++)
        
            char c = (char)i;

            // in case a letter didn't appear at all in the input string
            if (!indices.ContainsKey(c)) continue;

            List<int> indexList = indices[c];

            // in case a letter appeared only once in the input string
            if (indexList.Count == 1) max = Math.Max(max, 1);

            for (int j = 0; j < indexList.Count; j++)
            
                for (int k = j + 1; k < indexList.Count; k++)
                
                    int dist = indexList[k] - indexList[j] + 1;
                    string sub = s.Substring(indexList[j], dist);
                    if (isPalendrome(sub, c)) 
                                        max = Math.Max(max, dist);
                   
            
        

        return max;
    

    bool isPalendrome(string s, char c)
    
        int i = 0;
        while(i < s.Length - 1 - i) 
        
            if (s[i] != c && s[s.Length - 1 - i] != c) 
            
                i++;
                continue;   
            
            if (s[i] != s[s.Length - 1 - i]) return false;
            i++;
        
        return true;
    

【讨论】:

以上是关于如何有效地确定给定字符串中最长的单个字符回文?的主要内容,如果未能解决你的问题,请参考以下文章

最长回文字符串

最长回文字符串

最长回文字符串

最长回文子串

在 Python 中查找字符串中最长的回文

给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢? 输出需要删除的字符个数。