【问题标题】:given an array of sorted ints, find the most frequently occuring element in log(n)给定一个有序整数数组,找出 log(n) 中出现频率最高的元素
【发布时间】:2018-04-04 08:10:08
【问题描述】:

在 O(n) 中很容易找到出现频率最高的元素。 是否有更快的算法(O(logn))来做到这一点? (给定数组已排序)

【问题讨论】:

  • 如果我们有一个数组,例如 a = [1, 2, 2, 2, 4, 7, 7] 你想得到 2 作为结果吗?
  • 是的。没错
  • 我不理解反对票。这是一个合法的问题。我在一家大型科技公司的采访中被问到
  • 我没有投反对票 :)
  • 这家伙非常确信有一个 O(logn) 算法。他的提示是关于按步/增量(> 1)跳过,而不是按 1 递增……我不记得细节了

标签: algorithm search binary


【解决方案1】:

这是不可能的。下面不是一个严格的证明(严格的下界证明通常很难),而是一个理智的推理。

假设您的数组总是看起来像1, 2, 3, 4, 5, 6, ..., n。然后,您将某个数字替换为之前出现的数字:1, 2, 3, 3, 5, ... n。现在在新数组 a[i] = i 中,除了一个位置之外的所有 i

为了找到最频繁的元素,您必须检查所有位置并检查那里的不规则性。请注意,只有一个不规则性,如果您查看数组的任何其他元素,您就无法说出它的位置。因此,这个问题并不比在 1 和 0 的布尔数组中找到 one 容易,这需要线性时间。

【讨论】:

  • 那家伙(面试官)告诉我,通过执行诸如跳过 delta d 而不是 1 之类的操作,有一个 o(logn) 。例如。你在 num[i] 看到一个值 x,你跳到 num[i+d],如果它仍然是 x,继续,否则,备份......类似的东西。我并不是说他 100% 正确(他可能是错的),但可以公平地假设他知道自己在做什么
  • @OneTwoThree 面试官有时也会犯错误。或者,也许你误解了这个问题?也许它被要求找到至少出现一半时间的元素(尽管在这种情况下问题是微不足道的)。我很确定我的示例表明您描述的问题可能不存在 O(log n) 时间算法。
  • 哦,想想看。也许你是对的。也许是“找到多数……(超过 50%)”……假设这是问题,你是如何解决的?
  • @OneTwoThree 如果我们需要这种多数,请查看位置 n/2 的元素(加减 1 取决于大小的奇偶校验)。如果您需要检查该元素是否确实占多数,请使用二分查找。
  • 我只是想在这里理解你的非正式证明。您说“用出现上一个数字替换一些数字”。然后,您将 4(第 3 个元素,从 0 开始)替换为“prev 的出现”数字,应该是 1,不是吗?我不明白你为什么用“3”替换“4”
【解决方案2】:

不是O(logn),但如果不同整数的数量较少,您可以在O(mlogn) 中解决它,其中 m 是不同整数的总数。

需要注意的是,这个解决方案只有m << n才会有成效。

这个想法是从索引 0 开始,并在排序后的数组中找到相同数字的最后一次出现,这可以使用二进制搜索通过跳过 delta d 来完成,正如你的面试官所说的那样,每次都增加这个 delta,直到你找到最后一个数字。

发现后,您可以拥有另一个变量 maxCount,它在开始时被初始化为 0。检查是否endIndex - startIndex > maxCount,如果是,将maxCount 替换为endIndex - startIndex。现在,从startIndex+1 开始重复相同的过程。

正如@ivan 上面提到的,如果所有数字都不同,这将非常失败,并且会给出 O(n) 解决方案。

【讨论】:

    【解决方案3】:

    此 Python 代码根据 @Parijat 的回答在 O(mlogn) 时间完成。

    import bisect
    
    def most_frequent_in_sorted(lst):
        most_frequent = None
        max_frequency = 0
        n = len(lst)
        idx = 0
    
        while idx < n:
            # Get leftmost index holding an element != lst[idx]
            next_leftmost_idx = bisect.bisect_right(lst, lst[idx])
    
            # Update most frequent element
            cur_frequency = next_leftmost_idx - idx
            if cur_frequency > max_frequency:
                most_frequent = lst[idx]
                max_frequency = cur_frequency
    
            # Update index to hold next different integer
            idx = next_leftmost_idx
    
        return most_frequent
    

    【讨论】:

      猜你喜欢
      • 2019-08-31
      • 2017-07-18
      • 2019-08-15
      • 1970-01-01
      • 2012-11-03
      • 2013-03-21
      • 2021-02-27
      • 2012-02-12
      • 2011-09-09
      相关资源
      最近更新 更多