算上仙境

时间:2015-07-24 16:06:51

标签: algorithm math

text of Alice in Wonderland包含8次“仙境”这个词。 (让我们对这个问题不区分大小写)。

然而,如果你计算非连续的子序列以及子串,它会多次包含这个词,例如。

  

要么井很深,要么她很慢,因为她有   她有很多时间去看她和 WONDER 是什么   接下来会发生。首先,她试图 L ook down AND 弄明白了   她来了,但是看不到任何东西太黑了;

(子序列是一个序列,可以通过删除一些元素而不改变其余元素的顺序从另一个序列派生。-Wikipedia)

这本书包含仙境这个词作为一个子序列多少次?我希望这将是一个很大的数字 - 这是一本很长的书,有许多w和o和n和s。

我尝试了强力计数(递归使得循环10深)但它太慢了,即使对于那个示例段落也是如此。

3 个答案:

答案 0 :(得分:10)

我们假设您不想搜索var message = new Buffer('HIA'); udpServer.send(message, 0, message.length, ...) ,而只是wonderland。然后,您只需计算故事中w发生的次数。

现在让我们说你想要w。对于您找到的当前模式的每个第一个字符,您可以添加到计数中:

  1. 在故事的其余部分出现没有第一个字符的当前模式的次数,在此字符之后:您已将问题wo简化为{{1} }

  2. 整个当前模式在故事的其余部分出现了多少次。因此,您已将问题缩减为(story[1..n], pattern[1..n])

  3. 现在你可以添加两个。如果我们谈论子问题,就没有过度计算。考虑示例(story[2..n], pattern[2..n])。显然,(story[2..n], pattern[1..n])发生wawo次。你可能会认为计数会像:

    1. 对于第一个wo,请添加2,因为w会在1之后发生,而另一个o因为1在其之后发生一次。< / p>

    2. 对于第二个wo,请添加w,因为1之后会发生一次。

    3. 答案是o,这是错误的。

    4. 但这是实际发生的事情:

      3

      所以你可以看到答案是(wawo, wo) -> (awo, o) -> (wo, o) -> (o, o) -> (-, -) -> 1 -> (-, o) -> 0 -> (awo, wo) -> (wo, wo) -> (o, wo) -> (-, wo) -> 0 -> (o, o) -> (-, -) -> 1 -> (-, o) -> 0

      如果您找不到2,则此排名的计数是此当前字符后w出现的次数。

      这允许使用memoization进行动态编程:

      wo

      使用count(story_index, pattern_index, dp): if dp[story_index, pattern_index] not computed: if pattern_index == len(pattern): return 1 if story_index == len(story): return 0 if story[story_index] == pattern[pattern_index]: dp[story_index, pattern_index] = count(story_index + 1, pattern_index + 1, dp) + count(story_index + 1, pattern_index, dp) else: dp[story_index, pattern_index] = count(story_index + 1, pattern_index, dp) return dp[story_index, pattern_index] 致电。请注意,您可以使代码更清晰(删除重复的函数调用)。

      Python代码,没有任何记忆:

      count(0, 0, dp)

      输出:

      def count(story, pattern):
        if len(pattern) == 0:
          return 1
        if len(story) == 0:
          return 0
      
        s = count(story[1:], pattern)
        if story[0] == pattern[0]:
          s += count(story[1:], pattern[1:])
      
        return s
      
      print(count('wonderlandwonderland', 'wonderland'))
      

      这是有道理的:对于故事的第一个17 中的每个i个第一个字符,您可以将其与第二个wonderland中剩余的最终字符进行分组,为您提供{{1解决方案。另一个wonderland是单词本身。其他五个是:

      10

      你是对的,这将是一个巨大的数字。我建议您使用大整数或以模数形式取结果。

      同一程序会为您的示例段落返回2

答案 1 :(得分:3)

字符串“wonderland”作为 Alice in Wonderland 1 24100772180603281661684131458232次的子序列出现。

主要思想是逐个字符地扫描主文本,保持目标字符串的每个前缀的频率的运行计数(即:在这种情况下,“w”,“wo”,“won”,... 。,“wonderlan”和“仙境”)已经发生在当前的信件中。这些运行计数易于计算和更新。如果当前的字母没有出现在“仙境”中,则计数保持不变。如果当前的字母是“a”,那么我们增加“wonderla”的数量,看看到目前为止看到的“wonderl”的数量。如果当前字母是“n”,那么我们将“won”的计数增加“wo”的计数,并将“wonderlan”的计数增加“wonderla”的计数。等等。当我们到达文本的末尾时,我们将根据需要计算“wonderland”的所有前缀,包括字符串“wonderland”本身。

这种方法的优点是它需要单次传递文本,并且不需要O(n)递归调用(除非你做一些聪明的事情,否则它可能超过最大递归深度。)

代码

import fileinput
import string

target = 'wonderland'

prefixes = dict()
count = dict()

for i in range(len(target)) :
    letter = target[i]
    prefix = target[:i+1]
    if letter not in prefixes :
        prefixes[letter] = [prefix]
    else :
        prefixes[letter].append(prefix)
    count[prefix] = 0L

for line in fileinput.input() :
    for letter in line.lower() :
        if letter in prefixes :
            for prefix in prefixes[letter] :
                if len(prefix) > 1 :
                    count[prefix] = count[prefix] + count[prefix[:len(prefix)-1]]
                else:
                    count[prefix] = count[prefix] + 1

print count[target]
  1. 使用Project Gutenberg的this text,从“第一章下兔子洞”开始,以“THE END”结尾

答案 2 :(得分:0)

对以前的评论进行跟进,如果您正在寻找一个针对2输入wonderlandwonderland而针对1返回wonderwonderland的算法,那么我认为您可以从这个问题中调整算法:

How to find smallest substring which contains all characters from a given string?

实际上,你的案例的变化是,一旦找到一个单词的实例,你就增加一个计数器并用文本的剩余部分重复所有的程序。

O(n)是文本的长度时,此类算法将nO(m)在空格中m是搜索字符串的长度。