【发布时间】: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 < low || a[mid - 1] < x/mid + 1 > high || a[mid + 1] > x条件,即当low == high作为结果low = mid + 1或high = mid - 1。 (另外,为了提高效率,您可以使用low = first开始第二部分。) -
@EricPostpischil:
!(mid - 1 < low)暗示a[mid - 1]在界限内。 -
@EricPostpischil mid - 1 high 用于检查我是否不在数组范围内
-
@EricPostpischil 我假设 x 将始终在数组中
-
你说得对,忽略我的其余代码,只注意我试图找到最后一次出现 x 的部分,你明白我的意图吗?
标签: c binary-search