如何获得字符串的最短回文

时间:2011-04-11 06:22:55

标签: c++ c

例如:

字符串是:abcd

最短的回文是abcdcba是解决方案

更长的回文可以是:abcddcba

另一个例子:

字符串:aaaab

最短的回文是aaaabaaaa

较长的回文可以是aaaaabbaaaa

限制:您最后只能添加字符。

11 个答案:

答案 0 :(得分:10)

只需将字符串的初始子串(从最短到最长)的反向追加到字符串,直到你有一个回文。例如,对于“acbab”,尝试附加“a”,其产生“acbaba”,这不是回文,然后尝试附加“ac”反转,产生“acbabca”,这是一个回文。

更新:请注意,您不必实际执行追加操作。你知道子串匹配,因为你只是颠倒了它。因此,您所要做的就是检查字符串的其余部分是否为回文,如果是,则追加子字符串的反向。这是Ptival象征性地写的,所以他应该得到答案的功劳。示例:对于“acbab”,找到最长的后缀,即回文;那就是“bab”。然后将剩余部分“ac”反向追加:ac bab ca。

答案 1 :(得分:7)

我对逻辑的猜测:

假设你的字符串是[a1 ... an](字符a1到a的列表)

  • 找出最小的i,以便[ai ... an]是回文。
  • 最小的回文是[a1 ... a(i-1)] ++ [ai ... an] ++ [a(i-1)... a1]

其中++表示字符串连接。

答案 2 :(得分:1)

一些伪代码,至少给你留下一些工作:

def shortPalindrome(s):
  for i in range(len(s)):
    pal = s + reverse(s[0:i])
    if isPalindrome(pal):
      return pal
  error()

答案 3 :(得分:1)

Python代码,应该很容易转换为C:

for i in range(1, len(a)):
    if a[i:] == a[i:][::-1]:
        break
print a + a[0:i][::-1]

答案 4 :(得分:1)

最近我也被问到了同样的问题,这就是我为我的采访所写的内容:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int isPalin ( char *str ) {
    int i, len=strlen(str);
    for (i=0; i<len/2; ++i)
        if (str[i]!=str[len-i-1])
            break;
    return i==len/2;
}

int main(int argc, char *argv[]) {
    if (argc!=2)
        puts("Usage: small_palin <string>");
    else {
        char *str = argv[1];
        int i=0, j, len=strlen(str);
        while ( !isPalin(str+i) )
            ++i;
        char *palin = malloc(len+1+i);
        *(palin+len+1+i) = '\0';
        strcpy(palin,str);
        for (i=i-1, j=0; i>=0; --i, ++j)
            *(palin+len+j) = str[i];
        puts(palin);
    }
    return 0;
}

如果我编写了strrev()函数并使用strcmp()检查了回文,我觉得该程序会更结构化。这将使我能够反转源字符串的起始字符,并使用strcpy()直接复制它。

为什么我选择这个解决方案的原因是,在这个问题之前,我被要求检查回文并且我已经在纸张中找到了那个isPalin()。使用现有代码的感觉会更好!!

答案 5 :(得分:0)

从您显示的示例看起来最长的回文是与其反向连接的原始字符串,最短的是与其反向连接的原始字符串,但第一个字符除外。但我很确定你想要更复杂的东西。也许你可以举出更好的例子?

答案 6 :(得分:0)

如果字符串由k个字符组成,我认为你应该在这个字符串中添加反向(k-1)字符......

答案 7 :(得分:0)

下面是我对另一个案例的回答:通过将字符附加到前面来获得最短的回文。所以你的任务是理解算法并适当地修改它。 基本上,它声明从字符串s中通过在s的前面添加一些字符来找到最短的回文。

如果您从未尝试解决此问题,我建议您解决此问题,这将有助于您提高解决问题的能力。

解决之后,我一直在寻找更好的解决方案。我偶然发现了另一个程序员的解决方案。它是在python中,非常整洁。这真的很有趣,但后来我发现这是错误的。

class Solution:
    # @param {string} s
    # @return {string}
    def shortestPalindrome(self, s):
        A=s+s[::-1]
        cont=[0]
        for i in range(1,len(A)):
            index=cont[i-1]
            while(index>0 and A[index]!=A[i]):
                index=cont[index-1]
            cont.append(index+(1 if A[index]==A[i] else 0))
        print cont[-1]
        return s[cont[-1]:][::-1]+s

我自己看了解决方案并看到了它有趣的想法。首先,该算法连接字符串及其反转版本。然后,以下步骤类似于在KMP算法中使用构建KMP表(或失败函数)的步骤。为什么这个程序有效?

如果你知道KMP文本搜索算法,你就会知道它的查找表&#34;以及构建它的步骤。现在,我只是展示了表的一个重要用途:它可以显示字符串s的最长前缀,也是s的后缀(但不是s本身)。例如,&#34; abcdabc&#34;具有最长的前缀,也是后缀:&#34; abc&#34; (不是&#34; abcdabc&#34;因为这是整个字符串!!!)。为了让它变得有趣,我们称这个前缀为&#34; happy substring&#34; s。所以&#34; aaaaaaaaaa&#34;的快乐子串(10 a&#39; s)是&#34; aaaaaaaaa&#34; (9 a&#39; s)。

现在我们回过头来看看如何找到快乐的子串可以帮助解决最短的回文问题。

假设q是添加到s前面的最短字符串,以使字符串qs为回文结构。我们可以看到显然长度(q)<长度(s)因为ss也是回文。由于qs是回文,qs必须以q结尾,或s = p + q,其中p是s的子串。很容易我们看到p也是回文。因此,为了具有最短的q,q需要最短。反过来,p是s中最长的回文子串。

我们称s&#39;和q&#39;是s和q的反向字符串。我们看到s = pq,s&#39; = q&#39; p因为p是回文。所以ss&#39; = pqq&#39; p。现在我们需要找到最长的p。找到了!这也意味着p是字符串ss&#39;的快乐子字符串。这就是上述算法的工作原理!!!

然而,经过一番思考,上述算法存在一些漏洞。 p不是一个快乐的子串ss&#39;!实际上,p是最长的前缀,也是ss&#39;的后缀,但前缀和后缀不能相互重叠。所以,让它变得更有趣,我们称之为非常快乐的子字符串&#34;字符串s是s的最长子字符串,它是一个前缀,也是一个后缀,这个前缀和后缀不能重叠。换句话说,&#34;非常快乐的子字符串&#34; s的长度必须小于或等于s的一半长度。

所以它结果是&#34;快乐的子字符串&#34; ss&#39;并不总是&#34;非常快乐的子串&#34; ss&#39;。我们可以很容易地构建一个例子:s =&#34; aabba&#34;。 SS&#39; =&#34; aabbaabbaa&#34 ;. &#34; aabbaabbaa&#34;的快乐子字符串是&#34; aabbaa&#34;,而非常快乐的子串&#34; aabbaabbaa&#34;是&#34; aa&#34;。砰!

因此,正确的解决方案应该如下,基于长度(p)<=长度(ss&#39;)/ 2的观察结果。

class Solution:
    # @param {string} s
    # @return {string}
    def shortestPalindrome(self, s):
        A=s+s[::-1]
        cont=[0]
        for i in range(1,len(A)):
            index=cont[i-1]
            while(index>0):
                if(A[index]==A[i]):
                    if index < len(s):
                        break
                index=cont[index-1]
            cont.append(index+(1 if A[index]==A[i] else 0))
        print cont[-1]
        return s[cont[-1]:][::-1]+s 

万岁! 如您所见,算法很有意思!

我写的here

文章的链接

答案 8 :(得分:0)

看起来这里列出的解决方案是O(N ^ 2)(对于反向字符串S的每个后缀X,找到S + X是回文)。

我相信这个问题有一个线性的,即O(N)解决方案。请考虑以下语句:唯一的时间是您添加的字符数少于S.Length - 1表示字符串已包含部分回文,因此它将采用NNNNNPPPPPP的形式,其中PPPPP表示回文。这意味着如果我们能够找到最大的尾随回文,我们可以通过将NNNNN的反向连接到末尾来线性地求解它。

最后,存在一种着名的算法(Manacher,1975),它找到了一个字符串中包含的最长(实际上是所有)的回文(有一个很好的解释here)。它可以很容易地修改,以返回最长的尾随的palidrome,从而为这个问题提供线性解决方案。

如果有人有兴趣,这里是镜像问题的完整代码(在开头添加字符):

   using System.Text;

    // Via http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html
    class Manacher
    {
        // Transform S into T.
        // For example, S = "abba", T = "^#a#b#b#a#$".
        // ^ and $ signs are sentinels appended to each end to avoid bounds checking
        private static string PreProcess(string s)
        {
            StringBuilder builder = new StringBuilder();

            int n = s.Length;
            if (n == 0) return "^$";

            builder.Append('^');

            for (int i = 0; i < n; i++)
            {
                builder.Append('#');
                builder.Append(s[i]);
            }

            builder.Append('#');
            builder.Append('$');

            return builder.ToString();
        }

        // Modified to return only the longest palindrome that *starts* the string
        public static string LongestPalindrome(string s)
        {
            string T = PreProcess(s);
            int n = T.Length;
            int[] P = new int[n];
            int C = 0, R = 0;
            for (int i = 1; i < n - 1; i++)
            {
                int i_mirror = 2 * C - i; // equals to i' = C - (i-C)

                P[i] = (R > i) ? Math.Min(R - i, P[i_mirror]) : 0;

                // Attempt to expand palindrome centered at i
                while (T[i + 1 + P[i]] == T[i - 1 - P[i]])
                    P[i]++;

                // If palindrome centered at i expand past R,
                // adjust center based on expanded palindrome.
                if (i + P[i] > R)
                {
                    C = i;
                    R = i + P[i];
                }
            }

            // Find the maximum element in P.
            int maxLen = 0;
            int centerIndex = 0;
            for (int i = 1; i < n - 1; i++)
            {
                if (P[i] > maxLen 
                    && i - 1 == P[i] /* the && part forces to only consider palindromes that start at the beginning*/)
                {
                    maxLen = P[i];
                    centerIndex = i;
                }
            }

            return s.Substring((centerIndex - 1 - maxLen) / 2, maxLen);
        }
    }
    
public class Solution {
    public string Reverse(string s)
    {
        StringBuilder result = new StringBuilder();
        for (int i = s.Length - 1; i >= 0; i--)
        {
            result.Append(s[i]);
        }
        return result.ToString();
    }
    

        public string ShortestPalindrome(string s)
        {
            string palindrome = Manacher.LongestPalindrome(s);
            string part = s.Substring(palindrome.Length);
            return Reverse(part) + palindrome + part;
        }
}

答案 9 :(得分:0)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    public class Test
    {

    public static void shortPalindrome(string [] words){
    List<string> container = new List<string>(); //List of Palindromes

    foreach (string word in words )
    {
        char[] chararray = word.ToCharArray();
        Array.Reverse(chararray);
        string newText = new string(chararray);

        if (word == newText) container.Add(word); 
    }

    string shortPal=container.ElementAt(0);
    for(int i=0; i<container.Count; i++)
    {
        if(container[i].Length < shortPal.Length){
            shortPal = container[i];
        }

    }

    Console.WriteLine(" The Shortest Palindrome is {0}",shortPal);

    }

    public static void Main()
    {
    string[] word = new string[5] {"noon", "racecar","redivider", "sun", "loss"};
    shortPalindrome(word);
    }
    }

答案 10 :(得分:-1)

最短的回文 -

  • 从最后一个位置+ 1反向迭代到开始
  • Push_back元素

#include <iostream>
#include <string>
using namespace std ;

int main()
{
    string str = "abcd" ;
    string shortStr = str ;
    for( string::reverse_iterator it = str.rbegin()+1; it != str.rend() ; ++it )
    {
        shortStr.push_back(*it) ;   
    }
    cout << shortStr << "\n" ;
}

更长的回文可以更长。

Ex:abcd
更长的回文 - abcddcba,abcdddcba,...