数组比集合或映射更受欢迎吗?

4

最近我参加了一家位于美国加利福尼亚湾区的公司的面试。其中一个问题是简单地找出一个字符串是否有重复的字符(我已经简化了一个冗长的问题)。

eg:
input : "qwerrty"
output : True

我使用Python编写了这个代码。

我提供了一个使用set来追踪迭代中遇到的元素的解决方案。

然而,面试官希望我使用一个数组[255]来追踪遇到的字符。

虽然我对使用任何一种方法都比较熟悉,但我的观点是使用set,因为当我们使用数组时会浪费255个字符空间。这是因为(众所周知)我们最初创建一个arr[255]=0,所有元素都是零,然后将ASCII等价索引值增加1。

另一方面,集合仅在访问的元素上消耗内存。

既然他有点争论要在此情况下使用数组而不是集合/映射,我很好奇他是否在技术上是正确的。在这种情况下,数组比set/map更优吗?为什么?

2个回答

3
这个问题需要注意的一点是,如果字符串中可能出现的不同字符数只有C个,那么对于任何长度大于等于C+1的字符串,你都可以自动返回存在重复项,而无需查看字符串,因为其中的字符太多了,它们不可能全部是唯一的(这就是鸽笼原理在起作用)。这对于思考这个特定问题的结构非常重要。
接下来,请注意您甚至不需要一堆计数器。您只需要每个字符一个比特位,因为在遍历数组时,您只需要知道您是否曾经见过一个字符(1)或从未见过(0)。这意味着您需要每个字符一个比特位。如果您的字长为W,则意味着基于数组的解决方案需要大约C / W个机器字的存储空间。
让我们想象一下,您正在使用C = 256(例如,每个字符都是一个字节值)在一个字长为32位的机器上(W = 32)。这意味着您需要八个机器字来存储位数组,这是一种可以轻松初始化为0的可忽略的存储空间。现在,考虑您的集合实现。如果您使用哈希表,将会使用某种内部数组来存储所有内容。您还需要空间来存储有关哈希函数的信息,并且通常会在某个地方缓存集合的大小。这将占用大约三个机器字仅用于大小和哈希函数信息,剩下五个字的空间。如果哈希表是通用实现的,并且每个条目使用一个机器字,则您的方法仅在哈希表小于或等于四个条目时才能节省空间,这不太可能发生。如果您的哈希表经过优化并直接存储char值,则可以存储多达五个字的char(20个char)而没有任何冲突,但如果您尝试保持负载因子低,则可能在看到10个或更多字符后调整表格大小。因此,简而言之,除非您有一个非常短的字符串,否则哈希表方法可能会使用更多的内存,并且哈希的开销将很高。数组方法可能更快。
另一方面,假设您在字符串中存储任意Unicode字符。现在,C = 1,114,112(感谢维基百科),即使使用64位字长,您需要一个包含17,408个机器单词的数组才能存储可能字符的每个比特位。那是非常大的存储空间,初始化它需要一段时间。现在,如果您输入的字符串是“合理的”,而不是病态构建的,那么很有可能会在字符串中很早就发现重复元素(如果字符串完全随机,则根据生日悖论,平均只需要√(2C)个字符就会得到重复元素),因此构建哈希表可能需要更少的空间。但是,如果字符串是病态构建的,以至于每个字符都是唯一的,那么哈希函数的常数因子开销、哈希表调整大小等等将很可能意味着您的方法比基于数组的方法慢,但这是一个不寻常的用例。
总之:
- 如果可能字符数较小(例如ASCII),则基于数组的方法可能会更快且更节省内存。 - 如果可能字符数较大(例如Unicode),则基于数组的方法可能在合理输入上较慢且内存效率较低,但对于选择病态输入可能比基于哈希的方法更快。
这样说,除非代码在紧密循环中运行,否则除“只使用一个集合”之外的任何其他方法都会使代码难以阅读,而对程序整体效率的最小受益。出于这个原因,一个合理的答案是“除非有理由不使用集合,否则使用集合,并仅在数据支持它的情况下切换到基于数组的方法”。

2

我相信时间复杂度和空间复杂度的分析才是面试官真正想要的答案。 从空间方面来看,两种情况的复杂度都是O(N)。 从时间方面来看,将字符添加到集合中并不是O(1),但在数组中将数字添加1确实是O(1)。 因此,一般来说,使用数组将消耗相同数量的内存,但需要更少的时间。


这里的大O时间复杂度实际上并不是衡量效率的好指标,因为输入长度有一个有效的上界,并且参与运算的常数项将支配其他项。此外,如果集合由哈希表支持,则添加一个字符可能需要预期的O(1)时间。 - templatetypedef
@templatetypedef 我认为问题中没有提及输入长度的上限。您对哈希表的预期时间复杂度是正确的。它可能是最坏情况下的O(n)。 - user1537085
输入大小没有上限,但由于鸽巢原理,任何足够长的字符串都必须在某个地方发生碰撞。 - templatetypedef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接