【问题标题】:Find all elements that appear more than n/4 times in a sorted array查找排序数组中出现次数超过 n/4 的所有元素
【发布时间】:2017-11-20 18:07:45
【问题描述】:

我的问题类似于Find all elements that appear more than n/4 times in linear time,给你一个大小为n的数组,找出所有出现n/4次以上的元素,不同的是数组是排序的,运行时应该比O( n)。

我的做法是对每个元素在位置n/4、n/2和3*n/4的第一次出现做3次二分查找,由于数组是排序的,我们可以知道每个元素出现的次数是否多于n /4 次通过检查下一个 n/4 元素是否具有相同的值。

我用python3写了如下代码,大家觉得我的做法对不对,有什么可以简化的吗?:

import bisect

# return -1 if x doesn't exist in arr
def binary_search(arr, x):
    pos = bisect.bisect_left(arr, x)
    return pos if pos != len(arr) and arr[pos] == x else -1

def majority(arr):
    n = len(arr)
    output = []
    quarters = [arr[n//4],arr[n//2],arr[3*n//4]]

    # avoid repeating answer in output array
    if arr[n//4] == arr[n//2]:
        quarters.remove(arr[n//4])
        quarters.remove(arr[n//2])
        output.append(arr[n//2])
    if arr[n//2] == arr[3*n//4]:
        if arr[n//2] in arr:
            quarters.remove(quarters[n//2])
        if arr[3*n//4] in arr:
            quarters.remove(quarters[3*n//4])
        if arr[n//2] not in output:
            output.append(arr[n//2])

    for quarter in quarters:
        pos = binary_search(arr, quarter)
        if pos != -1 and pos+n//4 < len(arr) and arr[pos] == arr[pos+n//4]:
            output.append(arr[pos])
    return output

print(majority([1,1,1,6,6,6,9,145]))

【问题讨论】:

  • 我认为避免重复答案会使事情变得更加困难。你是正确的,如果一个元素出现 1/4 或更多的时间,它在quarter 中至少出现一次。但是您的删除方法是错误的。因为如果arr[n//4] == arr[n//2],那么您将两者都删除,但现在有一个更改是您删除了所有出现的事件。
  • NlogN 并不比 O(N) 好
  • @LuaiGhunim:但列表作为先决条件排序。
  • 您描述的方法听起来不对。例如,如果一个项目出现 (n/4)+1 次,它可以从例如位置 2 开始并在位置 (n/4)+2 结束。该元素将出现在位置 (n/4),但不会出现在位置 0 或 (n/2)。如果您的代码实现了您所描述的,那就错了。如果您的代码有效,那么它不会实现您所描述的内容。
  • @JimMischel:你有这方面的示例输入吗?如果 array[n/4] == 1,我的算法会找到第一次出现的 1,假设它在 2,然后它会检查 array[2+n/4] == array[2] 以验证它是否出现超过 n/4 次。

标签: python arrays algorithm python-3.x refactoring


【解决方案1】:

我觉得你想要的更像是:

Examine the element at position n/4
Do a binary search to find the first occurrence of that item.
Do a binary search to find the next occurrence of that item.
If last-first > n/4, then output it.

Repeat that process for n/2 and 3(n/4)

如果前一个项目超出下一个 n/4 标记,则有提前退出的机会。

【讨论】:

  • 在找到第一个匹配项后,不需要对下一次匹配项进行二分搜索。只需检查 first_occur_pos + n/4 看看它是否是相同的数字。
【解决方案2】:

我会做出以下改进。取位置 0、n/8、n/4、3n/8、...、n 处的 9 个值。您只需要考虑重复两次的值。

当你进行二分搜索时,你可以同时做两端。这样,如果最常见的值远小于或远大于 1/4,那么您就不需要进行大部分的二分搜索。

【讨论】:

  • 但是对于列表[1,1,2,3,4,5,6,7]1 的重复次数超过 1/4(2 次)。
  • @WillemVanOnsem 没问题,它会在第 8 次通过时显示为候选,然后二进制搜索失败。关键是O(1) 检查通常可以消除O(log(n)) 搜索。而O(log(n)) 搜索通常会在你这样做时短路。
猜你喜欢
  • 2014-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多