采访街找字符串

InterviewStreet Find Strings

本文关键字:字符串 访街      更新时间:2023-10-16

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

输入:

输入的第一行包含一个整数"n",表示字符串的数量。接下来的每一行"n"行都由一个字符串组成。第 i 行上的字符串 (1<=i<=n) 用 wi 表示,长度为 mi。下一行由单个整数"q"组成,表示查询数。接下来的每一行"q"都由一个整数"k"组成。

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

输出:

输出"q"行,其中第 i 行由一个字符串组成,该字符串是第 i 个查询的答案。如果输入无效("k"> |S|),在这种情况下输出"无效"(为清楚起见,用引号引起注意)。

约束:

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)

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

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

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

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

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

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

一个。后缀数组本身。

二.排名数组。

三.高度数组。

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

您会收到bad_alloc错误,因为内存中容纳了太多唯一的子字符串。为了纠正它,您可以使用任何不需要存储每个唯一子字符串的方法。

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

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

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

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

使用后缀数组...在内存上,它将比生成所有子字符串更快、更容易......如果您对后缀数组进行排序,然后尝试使用一些增强数据结构进行搜索,例如LCP 数组和累积子字符串计数数组,您可以在内存限制内及时解决它。