给出一个单词,将其转换为回文,最少添加字母

时间:2012-03-10 19:26:51

标签: string algorithm palindrome

这是一个非常有趣的采访问题:

  

给出一个单词,将最少数量的字母附加到它以将其转换为回文。

例如,如果“hello”是给定的字符串,则结果应为“hellolleh”。如果给出“coco”,结果应该是“cococ。”

我能想到的一种方法是将字符串的反向追加到原始字符串的末尾,然后尝试从末尾消除额外的字符。但是,我无法弄清楚如何有效地做到这一点。有没有人有任何想法?

4 个答案:

答案 0 :(得分:10)

好!这是我的第二次尝试。

我们的想法是,我们想要在附加额外字符以完成回文时,找到字符串末尾有多少字符可以重复使用。为此,我们将使用KMP字符串匹配算法的修改。使用KMP,我们搜索原始字符串的反向。一旦我们到达字符串的最后,我们将在字符串的反向和字符串末尾出现的原始字符串之间尽可能多地匹配。例如:

HELLO
    O

1010
 010

3202
 202

1001
1001

此时,KMP通常会说“不匹配”,除非原始字符串是回文。但是,由于我们目前知道字符串的反向匹配了多少,我们可以只计算出仍然缺少多少个字符,然后将它们添加到字符串的末尾。在第一种情况下,我们遗漏了LLEH。在第二种情况下,我们遗漏了1。第三,我们缺少3。在最后一种情况下,我们没有遗漏任何东西,因为最初的字符串是回文。

此算法的运行时是标准KMP搜索的运行时间加上反转字符串所需的时间:O(n)+ O(n)= O(n)。

所以现在要争论正确性。这需要一些努力。考虑最佳答案:

   | original string | | extra characters |

让我们假设我们从末尾开始向后阅读,这意味着我们至少会读取原始字符串的反向。这个反向弦的一部分向后延伸到原始弦本身的主体中。实际上,为了最小化添加的字符数,这必须是最终可能返回字符串本身的字符数。我们可以在这里看到:

   | original string | | extra characters |
           | overlap |

现在,我们的KMP步骤会发生什么?好吧,当在内部查找字符串的反向时,KMP将始终保持尽可能长的匹配,因为它在字符串中工作。这意味着当KMP命中字符串的末尾时,它维护的匹配部分将是最长的匹配,因为KMP仅在失败时向前移动候选匹配的起始点。因此,我们有尽可能长的重叠,所以我们将在最后得到尽可能短的字符数。

我不是百分之百确定这是否有效,但似乎这种情况适用于我可以投入的每一种情况。正确性证明似乎是合理的,但它有点手工波浪,因为正式的基于KMP的证​​明可能有点棘手。

希望这有帮助!

答案 1 :(得分:5)

要回答我会采取这种天真的方法:

  1. 什么时候我们需要0个字符?当字符串它是一个回文
  2. 当我们需要1个角色?除了第一个字符串是回文
  3. 什么时候需要2个字符?除了2个开始字符外,字符串是回文
  4. 等等...
  5. 所以算法可以

      for index from 1 to length
       if string.right(index) is palindrome
        return string + reverse(string.left(index))
       end
      next
    

    修改

    我不是一个Python人,但上面伪代码的简单实现可能是

    >>> def rev(s): return s[::-1]
    ... 
    >>> def pal(s): return s==rev(s)
    ... 
    >>> def mpal(s):
    ...  for i in range(0,len(s)):
    ...   if pal(s[i:]): return s+rev(s[:i])
    ... 
    >>> mpal("cdefedcba")
    'cdefedcbabcdefedc'
    >>> pal(mpal("cdefedcba"))
    True
    

答案 2 :(得分:4)

简单的线性时间解决方案。

让我们调用我们的字符串S.

设f(X,P)为X和P的最长公共前缀的长度。计算f(S [0],rev(S)),f(S [1],rev(S)), ...其中S [k]是从位置k开始的S的后缀。显然,你想选择最小k,使得k + f(S [k],rev(S))= len(S)。这意味着你必须在最后添加k个字符。如果k为0,则刺痛已经是一个回文。如果k = len(S),那么你需要追加整个反向。

我们需要快速计算所有S [i]的f(S [i],P)。这是棘手的部分。创建一个S的后缀树遍历树并用P的最长公共前缀的长度更新每个节点。叶子上的值对应于f(S [i],P)。

答案 3 :(得分:2)

首先制作一个函数来测试回文结构的字符串,记住“a”和“aa”是回文。他们是回文,对吗???

如果输入是回文,请将其返回(需要添加0个字符) 从x [length]向下循环到x [1],检查字符串x [i] .. x [length]的子集是否是回文,找到最长的回文。

在最长的回文之前从输入字符串中取出子串,将其反转并将其添加到最后应该通过追加得到最短的回文。

coco => c + oco => C + OCO + C

mmmeep => mmmee + p => mmmee + P + eemmm