InterviewStreet查找字符串

时间:2012-06-29 14:18:42

标签: c++ string algorithm set

给你'n'个字符串w1,w2,......,wn。设Si表示通过考虑字符串wi的所有唯一子串而形成的字符串集。子字符串被定义为字符串中一个或多个字符的连续序列。有关子串的更多信息,请参见此处。设'S'= {S1 U S2 U .... Sn} .i.e'S'是通过考虑所有组S1,S2,...... Sn中的所有唯一字符串而形成的一组字符串。您将获得许多查询,并且对于每个查询,您将获得整数'k'。您的任务是从集合'S'输出按字典顺序排列的第k个最小字符串。

输入:

第一行输入包含一个整数'n',表示字符串的数量。每个下一个'n'行由一个字符串组成。第i行上的字符串(1 <= i <= n)由wi表示并且具有长度mi。下一行包含一个整数'q',表示查询的数量。每个下一个'q'行由一个整数'k'组成。

注意:输入字符串仅由小写英文字母'a' - 'z'组成。

输出:

输出'q'行,其中第i行由一个字符串组成,该字符串是第i个查询的答案。如果输入无效('k'&gt; | S |),则为该情况输出“INVALID”(为清晰起见)。

约束:

1<=n<=50
1<=mi<=2000
1<=q<=500
1<=k<=1000000000

https://www.interviewstreet.com/challenges/dashboard/#problem/4efa210eb70ac

我的方法

对于每个输入字符串,生成其子字符串并将它们添加到集合中,这将自动消除重复项并保持它们的排序。在集合中返回索引i处的元素。

我在这里写了一个关于上述方法的代码:

http://justprogrammng.blogspot.com/2012/06/interviewstreet-find-strings-solution-c.html

但我面临的问题是

terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)

此错误出现在少数测试用例中。有人可以告诉我为什么我会收到此错误,我该如何纠正此错误?

3 个答案:

答案 0 :(得分:3)

@ enjay的回答是正确的。我会详细说明任何对这种字符串处理算法问题不熟悉的人,并希望了解更多信息。我的回答将描绘大局,并指出所提到的任何细节。

@sachin在interviewstreet.com中指出的问题属于一大堆问题,涉及子串,回文等。所有这些问题都可以通过一个专用数据结构来解决:后缀数组(en.wikipedia.org/wiki/Suffix_array)。完整的学习路径如下。但是,如果你只是在解决问题方面,你可以直接进入3。

  1. Trie树(http://en.wikipedia.org/wiki/Trie)。后缀树的基础。

  2. 后缀树(http://en.wikipedia.org/wiki/Suffix_tree)。将一个字符串的所有后缀放入Trie中。观察给定字符串的任何子字符串是给定字符串后缀之一的前缀。后缀树的想法是鼓舞人心的,但由于后缀树的构造要么太复杂而不能实现太慢,在实践中,我怀疑任何人都使用它。但是,对于任何想要挑战不必要的困难的人来说,这里是后缀树构造算法的最佳例证:http://stackoverflow.com/questions/9452701/ukkonens-suffix-tree-algorithm-in-plain-english

  3. 后缀数组(http://en.wikipedia.org/wiki/Suffix_array)。后缀数组包含后缀树所具有的任何信息(因此可以执行任何后缀树可以执行的操作)并且更容易实现。话虽这么说,如果你想用它完成任何非平凡的事情,你需要为RMQ构造至少三个数组和一个索引。这三个数组是:

  4. 一个。后缀数组本身。

    湾排名数组。

    ℃。高度数组。

    由于使用后缀数组时的一个常见任务是找到两个后缀的最长公共前缀,一个需要对高度数组进行RMQ查询。 RMQ在此处描述:http://en.wikipedia.org/wiki/Range_Minimum_Query

答案 1 :(得分:2)

你得到bad_alloc错误,因为有太多独特的子字符串适合内存。要纠正它,您可以使用任何不需要存储每个唯一子字符串的方法。

我的解决方案非常复杂,所以我只提供算法草图。

可以只存储那些从w1,w2,......,wn中每个可能位置开始并在w1,w2,......结尾的子串。 WN。而不是整个子字符串,您只能存储指向其起始字符的指针。

要回答查询,您可以对所有查询进行排序,对所有子字符串进行排序。然后以下列方式迭代子字符串:从同一个字符开始获取所有子字符串,然后使用相同的第二个字符取所有子字符串,依此类推。换句话说,隐式构造一个trie,所有内部节点的权重为1,所有叶子节点的权重等于剩余唯一子字符串的长度,对应于此节点。并且您遍历此trie,计算每个节点权重的累积总和,并将其与下一个尚未处理的查询进行比较。一旦找到匹配项,就打印子字符串并继续trie遍历。

所有这些都需要不多的内存,但却非常渴望计算资源。但它可能会被优化。您可以使用显式trie来存储所有短子串(可能长度为1 .. 2或1 .. 3)。您也可以使用存储桶排序算法对较长的子字符串进行排序。

答案 2 :(得分:2)

使用后缀数组 ...它比内容所有子串更快更容易内存... 如果您对后缀数组进行排序,然后尝试使用一些扩充数据结构进行搜索 一个 lcp数组 cumulative-substring-count数组你可以及时解决它并在内存约束内....