【问题标题】:Finding the number of occurrences of a number in a sorted array with O(log(N)) in C?在C中使用O(log(N))查找排序数组中数字的出现次数?
【发布时间】:2022-01-10 07:23:16
【问题描述】:

如果我有一个排序数组arr[] 包含n eleemnts,我如何以O(logn) 的复杂度找到某个数字key 的出现次数?

例如: 对于

int arr[] = {0, 1, 2, 2, 6, 6, 6, 7};
int n = 8;
int key = 6;
int first, last;

我会收到3

我解决这个问题的方法是进行两次二进制搜索,一次搜索第一次出现key 的索引,然后将结果保存在int first 中。另一个搜索最后一次出现key 的索引,将结果保存在last 中。那么剩下要做的就是返回 last - first + 1.

但是当我开始编写问题时,我遇到了一个问题,我无法计算last 导致了奇怪的结果。我一直在尝试调试我的代码,但没有成功,有什么建议吗?

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

int ex2(int*, int, int);

int main()
{
    int arr[] = {1, 4, 6, 6, 6, 7, 7, 8, 11, 14, 22};
    printf("%d", ex2(arr, 11, 6));
    return 0;
}

int ex2(int* a, int n, int x)
{
    int low = 0, high = n - 1, mid, first = 0, last = 0;
    // bin first
    while (low <= high)
    {
        mid = (low + high) / 2;
        if (a[mid] == x)
        {
            if (mid - 1 < low || a[mid - 1] < x)
            {
                first = mid;
                break;
            }
            else
                high = mid - 1;
        }
        if (a[mid] < x)
            low = mid + 1;
        else
            high = mid - 1;
    }
    // bin last
    low = 0;
    high = n - 1;
    while (low <= high)
    {
        mid = (low + high) / 2;
        if (a[mid] == x)
        {
            if (mid + 1 > high|| a[mid + 1] > x)
            {
                last = mid;
                break;
            }
            else
                low = mid + 1;
        }
        if (a[mid] < x)
            low = mid + 1;
        else
            high = mid - 1;
    }
    return last - first + 1;

}

当我运行它时:

    int arr[] = {1, 4, 6, 6, 6, 7, 7, 8, 11, 14, 22};
    printf("%d", ex2(arr, 11, 6));

我得到 -1(因为 last 仍然是 0 不像 first 持有正确的值 2 - > 0 - 2 + 1 = -1)。 当我得到 3 时(6 出现 3 次)。

【问题讨论】:

  • 您忘记设置 first/last 时到达循环结束而从未触发 mid - 1 &lt; low || a[mid - 1] &lt; x/mid + 1 &gt; high || a[mid + 1] &gt; x 条件,即当 low == high 作为结果low = mid + 1high = mid - 1。 (另外,为了提高效率,您可以使用low = first 开始第二部分。)
  • @EricPostpischil: !(mid - 1 &lt; low) 暗示 a[mid - 1] 在界限内。
  • @EricPostpischil mid - 1 high 用于检查我是否不在数组范围内
  • @EricPostpischil 我假设 x 将始终在数组中
  • 你说得对,忽略我的其余代码,只注意我试图找到最后一次出现 x 的部分,你明白我的意图吗?

标签: c binary-search


【解决方案1】:

if (a[mid] &lt; x) 更改为 else if (a[mid] &lt; x) 它出现的两个地方。

否则,在a[mid] == x 并且您设置low(在第一次搜索中)或high(在第二次搜索中)的情况下,代码将进入a[mid] &lt; x 的此测试并设置其他绑定,不正确。插入 else 会排除这种情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 2016-04-09
    • 2020-01-22
    • 1970-01-01
    • 2023-01-16
    • 1970-01-01
    • 2019-02-01
    相关资源
    最近更新 更多