散列100个不同的值,范围为10亿

时间:2016-07-31 05:58:04

标签: c++ arrays algorithm hash

我最近在接受采访时被问到这个问题。我有一个n元素的数组。该数组只有100个不同的值。我需要打印每个数字的出现次数。

 1<=n<=10^6
 1<=A[i]<=10^12

预期的空间复杂度为O(k),其中k是数组中不同值的数量。

例如,1 2 3 2 1 4 3 2 4 2 3 1 2;这里k4。 首先我建议在stl中使用map,但他希望他实现我自己的数据结构。然后我建议对每个元素使用排序插入,就像在二叉搜索树中一样,但这会给出O(nlogn)的时间复杂度。他想要一个O(n)解决方案。我试着考虑任何哈希函数,但我无法想出任何这样的函数。我还试图考虑trie数据结构,但我将再次扫描每个数字的每个数字,从而再次给出O(nlogn)复杂度。有什么办法可以解决这个问题?

3 个答案:

答案 0 :(得分:1)

哈希表不保证O(n * k)的理论复杂度。但制作这样的东西很容易。

首先,我们需要对值概率分布做一些假设 - 让它统一(或者我们需要一些专门的散列函数)。

接下来,让我们选择哈希表大小,例如201个条目(因此它将小于50%)。

接下来,让哈希函数只是MonoGame.Framework\bin

然后使用具有201个条目对的开放寻址哈希表H []:A [i]或NULL;频率值。

答案 1 :(得分:1)

我认为哈希表是一个很好的解决方案,但我想面试官期望你建立自己的哈希表。

这是我在Python中提出的解决方案。我使用mod 100作为哈希函数并使用Separate chaining来处理冲突。

import random

N = random.randint(1, 10**6)
K = 100
HASH_TABLE_SIZE = 100

distinct = [random.randint(1, 10**12) for _ in range(K)]
numbers = [random.choice(distinct) for _ in range(N)]

hash_table = [[] for _ in range(HASH_TABLE_SIZE)]

def hash(n):
    hash_key = n % HASH_TABLE_SIZE
    bucket = hash_table[hash_key]
    for value in bucket:
        if value[0] == n:
            value[1] += 1
            return
    bucket.append([n, 1])

for number in numbers:
    hash(number)

for bucket in hash_table:
    for value in bucket:
        print('{}: {}'.format(*value))

修改

稍微解释一下代码:

我的哈希表是一个100个元素的数组。数组中的每个条目都是(number, count)个条目的列表。要散列数字,我将其值取模100来查找数组的索引。我扫描那个桶中已有的数字,如果它们中的任何一个与当前数字匹配,我会增加它的计数。如果我找不到该号码,我会在列表中附加一个新条目,其中包含数字和初始计数为1。

从视觉上看,数组看起来像这样:

[
  [ [0, 3], [34500, 1] ]
  [ [101, 1] ],
  [],
  [ [1502, 1] ],
  ...
]

请注意,在索引 n 中,存储在存储桶中的每个值等于 n (mod 100)。平均而言,每个桶只有一个值,因为阵列中最多有100个不同的值和100个元素。

要打印出最终的计数,所需要的只是遍历阵列和每个桶中的每个条目并打印出来。

编辑2

这是一个稍微不同的实现,它使用Open addressing代替线性探测。我想我其实更喜欢这种方法。

hash_table = [None] * HASH_TABLE_SIZE

def hash(n):
    hash_key = n % HASH_TABLE_SIZE

    while hash_table[hash_key] is not None and hash_table[hash_key][0] != n:
        hash_key = (hash_key + 1) % HASH_TABLE_SIZE

    if hash_table[hash_key] is None:
        hash_table[hash_key] = [n, 1]
    else:
        hash_table[hash_key][1] += 1

for number in numbers:
    hash(number)

for entry in hash_table:
    print('{}: {}'.format(*entry))

注意:如果实际上有超过100个不同的数字,此代码将失败。 (它将永远挂起,试图在阵列中找到一个空位。)保持检测到这种情况(例如,一旦你在阵列中走了整整一圈)并引发异常将是很好的。

答案 2 :(得分:1)

实际上,你错了,trie会给你O(N)复杂性。

trie的一次插入/查找/擦除操作需要O(L)时间,其中L是推入此trie的字符串的长度。幸运的是,您只需插入不超过1万亿的数字,这意味着L不大于log(10^12)(对数基数取决于您在此系列中使用的计数系统。我个人会选择{{1} }或256取决于此结构在整个系统的哪个部分发挥作用。)

总结一下,根据65536的定义,您需要O(N) * O(log(10^12))等于O(N)