算法建议:查找排序数组中的数字计数

Posted

技术标签:

【中文标题】算法建议:查找排序数组中的数字计数【英文标题】:Algorithm advice: Find count of number in sorted array 【发布时间】:2016-03-25 16:44:12 【问题描述】:

问题:

A = A[1]<=A[2]....A[n] 成为n 数字的排序数组。让x 成为一个数字。设计一个O(log n) 时间算法来找出x 在数组中出现的次数。时间复杂度是多少。

我的回答:

使用二进制搜索查找x = middle。如果x 在中间,那么x 有可能出现在中间的左右两侧。所以创建左数组L[] 和右数组R[]。使用二分搜索查找x 第一次出现在L[] 中。对R[] 做同样的事情,但要找到x 最后一次出现在R[] 中。注意索引。所以x出现的次数=Lastindex - FirstIndex + 1。时间复杂度 2log n + c = O(log n)。这只是算法的“骨架部分”,因为不必详细说明答案。这是我发现的,但有更好的解决方案吗?

【问题讨论】:

对我来说似乎不错(尽管有点过于复杂)。请注意,根据语言,创建 L[] 和 R[] 数组本身可能是 O(n) (这可以通过使用相同的数组并引用每个概念子数组中的第一个和最后一个索引来解决) @amit 感谢您的指出,我的意思是说子数组。感谢您的快速回放。 这个问题将受益于更好的标题和更好的格式,使其更易于阅读。 我看到你的回答有几个问题。 1.你说的是数组中间是x的情况,但如果不是x,你就再也回不去了。 2.没有理由创建单独的左右数组,只需对原始数组进行两次二进制搜索并找到索引即可。 【参考方案1】:

使用二分查找找到第一个元素的位置>=x(如果没有这样的元素,则使用结束),再使用二分查找找到第一个元素的位置>x。这些位置之间的差异是元素的数量 == x。

int countXs(int[] array, int len, int x)

    int low, high, test;
    for (low=0, high=len; low<high;)
    
        test = low+((high-low)>>1);
        if (array[test]>=x)
            high=test;
        else
            low=test+1;
    
    int startPos = low;
    for (low=0, high=len; low<high;)
    
        test = low+((high-low)>>1);
        if (array[test]>x)
            high=test;
        else
            low=test+1;
    
    int endPos = low;
    return endPos - startPos;

请注意,low+((high-low)&gt;&gt;1)floor((low+high)/2),但可以防止溢出。这总是&gt;= low&lt; high,所以我们可以安全地访问array[test]

【讨论】:

以上是关于算法建议:查找排序数组中的数字计数的主要内容,如果未能解决你的问题,请参考以下文章

排序算法之计数排序

一文弄懂计数排序算法!

一文弄懂计数排序算法!

排序算法 三计数与索引--计数排序使用的正确姿势

算法刷题-搜索旋转排序数组路径总和 II拆分数字

算法数据结构面试分享数组排序问题 - 计数排序