找到在给定的整数数组中以偶数频率出现的单个整数,当所有其他整数出现奇数频率时

时间:2012-01-18 00:40:36

标签: arrays algorithm data-structures integer

这是一个面试问题。

  

给定一个整数数组,找到数组中出现偶数频率的单个整数值。所有整数都是正数。所有其他数字出现奇数频率。数组中的最大数字可以是INT_MAX。

     

例如,[2,8,6,2]应返回2.

如果您可以找到更好的解决方案,例如O(1)空间和O(n)时间,则可以修改原始数组。

我知道如何通过哈希表(遍历和计数freq)来解决它。它是O(n)时间和空间。

是否有可能通过O(1)空间或更好的时间来解决它?

5 个答案:

答案 0 :(得分:6)

鉴于这是一个面试问题,答案是:O(1)空间是可以实现的“非常大的值1”:

  • 准备全部0
  • 的matcharray 1..INT_MAX
  • 遍历数组时,使用整数作为matcharray的索引,添加1
  • 完成后,遍历匹配数组以查找具有正偶数值的一个条目

这个空间很大,但与输入数组的大小无关,所以O(1)空间。对于非常大的数据集(比如小值范围,但是阵列长度很大),这甚至可能是一个实际有效的解决方案。

答案 1 :(得分:4)

如果允许对原始数组进行排序,我相信您可以在O(n lg U)时间和O(lg U)空间中执行此操作,其中U是数组的最大元素。这个想法如下 - 使用in-place MSD radix sort,在O(n lg U)时间和O(lg U)空间中对数组进行排序。然后,遍历数组。由于所有相等的值都是连续的,因此您可以计算每个值出现的次数。一旦找到偶数次出现的值,就可以输出答案。第二次扫描需要O(n)时间和O(1)空间。

如果我们假设U是固定常数,则给出O(n) - 时间,O(1) - 空间算法。如果你不假设这一点,那么内存使用率仍然优于O(n)算法,只要lg U = O(n),在大多数机器上都应该如此。此外,空间使用仅与最大元素对数一样大,这意味着实际空间使用非常好。例如,在64位计算机上,我们只需要足够的空间来容纳64个递归调用。这比预先分配一个巨大的数组要好得多。此外,这意味着该算法是一个弱多项式时间算法,作为U的函数。

也就是说,这会重新排列原始数组,从而破坏性地修改输入。从某种意义上说,它是作弊的,因为它将数组本身用于O(n)存储空间。

希望这有帮助!

答案 2 :(得分:1)

扫描列表,保持两组,“偶数”设置和“奇数”设置。如果之前没有看到过某个元素(即如果它们都没有被设置过),请将它放在“奇数”集中。如果元素在一个集合中,则将其移动到另一个集合。最后,'Even'集合中应该只有一个项目。这可能不会很快,但对于大型列表,内存使用应该是合理的。

答案 3 :(得分:0)

- 创建一个包含整数的哈希表。称之为is_odd或其他东西。由于您可能需要查看大小为INT_MAX的数组,因此只需将其设置为大小为INT_MAX的数组即可。初始化为0。

- 遍历整个阵列。你必须这样做。没有办法击败O(n)。

for each number:
  if it's not in the hash table, mark its spot in the table as 1.

  if it is in the hash table then:
    if its value is '1', make it '2'
    if its value is '2', make it '1'.

现在你必须遍历哈希表。拉出唯一的条目,以“2”作为值。

时间: 你遍历数组一次和哈希表一次,所以O(n)。

空间: 只是一个大小为INT_MAX的数组。或者,如果您知道阵列的范围,则可以将内存使用限制在此范围内。

编辑:我刚看到你已经有了这个方法。对不起!

答案 4 :(得分:-2)

我想我们不正确地阅读了这个任务。它要求我们“找到数组中出现偶数频率的单个整数值”。因此,假设只有一个偶数元素,解决方案是:

public static void main(String[] args) {
    int[] array = { 2, 1, 2, 4, 4 };

    int count = 0;
    for (int i : array) {
        count^=i;
    }
    System.out.println(count); // Prints 1
}