【问题标题】:Find a single integer that occurs with even frequency in a given array of ints when all others occur odd with frequency当所有其他整数以奇数频率出现时,在给定的整数数组中找到以偶数频率出现的单个整数
【发布时间】:2012-02-12 19:04:42
【问题描述】:

这是一道面试题。

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

例如,[2, 8, 6, 2] 应该返回 2。

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

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

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

【问题讨论】:

  • 你不能比检查每个元素至少一次(平均)做得更好,所以你不会超过 O(n) 时间。
  • 您甚至不必计算实际频率,只需计算模 2 的频率。;)
  • 是否有要超越的目标,或者这是一个“你能做到的最好的事情”的问题?
  • 可以修改原始数组吗?数字有界限吗?

标签: arrays algorithm data-structures integer


【解决方案1】:

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

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

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

【讨论】:

  • 来自OQ:“数组中的最大数可以是INT_MAX”
  • 我很抱歉;我错过了那个细节!
  • 没问题:事实上,考虑到问题的性质,我认为您的意见非常有价值!
  • @EugenRieck 我无法理解/找到 matcharray 是什么?它是某种特殊类型的数组吗?
  • @brainydexter 只是一个普通数组,我们用它来匹配某些东西(或者在这种情况下计数匹配)
【解决方案2】:

扫描维护两个集合的列表,“偶数”集合和“奇数”集合。如果一个元素以前没有出现过(即,如果它不在两个集合中),则将其放入“奇数”集合中。如果一个元素在一个集合中,则将其移动到另一个集合。最后,“偶数”集中应该只有一项。这可能不会很快,但对于大型列表,内存使用应该是合理的。

【讨论】:

  • 你能把它归结为大 O 时间和空间复杂度吗?
  • 这是 O(n) 时间,O(n) 空间。
  • 如果是 O(n) 时间,这意味着可以在 O(1) 上扫描单个项目,这意味着可以在 O(1) 中检查集合和交换项目。但我不明白这将如何运作。如何检查给定数字是否在 O(1) 的集合中?如果我们知道数字的范围(例如,所有数字都小于 100),那么我们可以使用该长度的数组来实现这一点。但我看不出我们如何处理 O(1) 中的任意大数字,它需要某种哈希集。我们是否允许使用大量内存来为我们提供 O(1) 的稀疏散列?
【解决方案3】:

如果允许你对原始数组进行排序,我相信你可以在 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) 的存储空间。

希望这会有所帮助!

【讨论】:

  • 我采用了 Eugen Rieck 的技术以及您的方法来获得不修改输入数组的解决方案。
  • @RajendranT 那可能是什么?
  • @brainydexter-该答案已被删除。这个想法是单独跟踪每个位的奇偶校验,但最终没有按预期工作。
【解决方案4】:

-制作一个包含整数的哈希表。称它为 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 的数组。或者,如果您知道数组的范围,则可以将内存使用限制在此范围内。

edit:我刚刚看到你已经有了这个方法。很抱歉!

【讨论】:

    【解决方案5】:

    我猜我们读错了任务。它要求我们“在数组中找到以偶数频率出现的单个整数值”。因此,假设恰好有一个偶数元素,解决方案是:

    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
    }
    

    【讨论】:

    • 1 在您的示例中出现的频率很奇怪。
    猜你喜欢
    • 2021-10-30
    • 2019-08-31
    • 2018-04-04
    • 1970-01-01
    • 2021-05-10
    • 2017-07-18
    • 2021-10-03
    • 2020-05-26
    • 1970-01-01
    相关资源
    最近更新 更多