【问题标题】:Counting palindromic substrings in O(n)计算 O(n) 中的回文子串
【发布时间】:2010-09-05 19:31:34
【问题描述】:

给定一个长度为n 的字符串(假设只有英文字符)S,我们可以使用以下算法计算回文子串的数量:

for i = 0 to |S| do
    p1 = number of palindromes centered in i (odd length)
    p2 = number of palindromes centered in i and i+1 (even length)

    add p1 + p2 to total number of palindromic substrings of S

上面的代码是O(n^2)

我对在O(n) 中解决此问题的算法感兴趣。我确定存在一个,因为我听到很多人说它确实存在,并且问题存在于本地在线法官网站上,n 上的上限为1 000 000,但是我从未见过该算法并且似乎无法想出它。

更新:

我的一般想法是计算len[i] = length of the longest palindrome centered at the character 2i + 1 和一个类似的数组,用于偶数长度的回文数。通过良好的簿记,应该可以在O(1) 中为每个字符计算此值,这将允许我们一次计算大量回文。但是,我不知道如何准确计算它。

我会接受使用O(n) 甚至O(n log n) 额外内存的解决方案。我认为没有它是不可能的。

感谢任何好的想法或参考。

【问题讨论】:

  • 是什么让您认为解决方案是 O(n) 时间?此外,有一个需要 O(n log n) 空间的 O(n) 时间算法也很奇怪。
  • @Strilanc - 我认为它是 O(n),因为这是某些人提到的复杂性,也是唯一可以在 0.1 秒内运行一百万个字符的复杂性。
  • @IVlad 如果你知道怎么做,你能把代码贴出来吗?

标签: algorithm string optimization count


【解决方案1】:

以下站点显示了一种在 O(n) 时间内计算最长回文子串的算法,它通过计算每个可能中心的最长回文子串然后取最大值来实现。因此,您应该能够根据自己的目的轻松修改它。

http://www.akalin.cx/2007/11/28/finding-the-longest-palindromic-substring-in-linear-time/

编辑:仔细检查后,第一个链接看起来有点不稳定,所以这是另一个链接:

http://zhuhcheng.spaces.live.com/Blog/cns!DE38E96268C49F28!311.entry?wa=wsignin1.0&sa=707413829

【讨论】:

  • 我真的不明白他们如何在您的第二个链接中计算 P[i]。你能澄清一下吗?我所看到的只是一些不等式,但没有关于如何实际计算 P 的内容。您的第一个链接在这方面要清楚得多,但有些人说它实际上是二次的。我将编写自己的实现并为自己测试。
  • 我将您第一个链接中的 python 代码翻译成 C++,它看起来像 O(n)。对于由单个字符组成的字符串,它会立即运行,并且它还通过了我尝试的所有测试。好像是这样,谢谢!
  • 这是关于最大回文的,并且每当找到更大的回文时它也会跳过小回文。我想知道您是否能够通过修改该算法来计算所有回文?
  • @IVlad 我喜欢第 70 行的 python 代码中的一个错误。else: 语句似乎不合适,我不确定它的正确位置。
  • @Paul:我不认为第一个链接是不稳定的,它们都是对同一个算法的描述,马纳赫算法。
【解决方案2】:

对于“普通”字符串,将每个字符视为回文的潜在“中心”,然后检查周围的字符是否确实构建了一个回文应该是相当有效的:

# check odd palindromes
for center in range(len(ls)):
   # check how many characters to the left and right of |center|
   # build a palindrome
   maxoffs = min(center, len(ls)-center-1)
   offs = 0
   while offs <= maxoffs and ls[center-offs] == ls[center+offs]:
      offs += 1
   offs -= 1
   print ls[center-offs : center+offs+1]                                    

# check for even palindromes
for center in range(len(ls)-1):
   maxoffs = min(center, len(ls)-center-2)
   offs = 0
   while offs <= maxoffs and ls[center-offs] == ls[center+offs+1]:
      offs += 1
   offs -= 1
   if offs >= 0:
      print ls[center-offs : center+offs+2]

对于普通字符串,这应该是 O(n) 左右,但在最坏的情况下,例如,如果字符串只包含一个反复重复的字符,它仍然需要 O(n2 sup>) 时间。

【讨论】:

  • 您确实可以提前停止搜索,这对于随机字符串来说已经足够了。不过,我对总是O(n) 的东西很感兴趣。打破这一点很容易:由单个字符组成的字符串。
【解决方案3】:

考虑一个字符串S="aaabb"

在字符串的两端和每两个连续字符之间附加一个字符'$',以将字符串更改为S="$a$a$a$b$b$",并将Manacher's algorithm应用于此字符串S

新字符串 S 的长度为 2n+1,这给了我们 O(2n+1) 的运行时间,与 O(n) 相同。

index :  1 2 3 4 5 6 7 8 9 10 11
A     :  1 3 5 7 5 3 1 3 5  3  1
S     :  $ a $ a $ a $ b $  b  $

数组 A 是 Manacher 算法的结果。

现在,A[i]/4 的总和对于索引 where '$',否则 (A[i]+1)/4 对于 1

这里,$ 作为偶数长度回文子串的中心,奇数长度可以正常计算。本案例的答案是:

0 + 1 + 1 + 2 + 1 + 1 + 0 + 1 + 1 + 1 + 0 = 9 (a,a,aaa,a,b,b,aa,aa,bb)。

【讨论】:

    猜你喜欢
    • 2020-05-13
    • 2014-01-21
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 2020-02-09
    • 2015-01-05
    相关资源
    最近更新 更多