我已尝试对给定元素进行二元搜索,并向左和向右遍历它,直到它得到的元素大于或小于它,但如果所有元素都相同,则直到O(n)时间复杂度。可以有更好的算法吗。
答案 0 :(得分:5)
您可以使用二进制搜索来查找范围的下限(和/或上限),并对下限进行二进制搜索,并对元素范围的上限或下限进行搜索大于你关心的那个。
编辑:我发现找到下限的大部分代码(我相信)比实际需要的要复杂得多。
int *find(int *left, int *right, int val) {
assert(left<right);
while (left < right) {
int *middle = left + (right - left) / 2;
if (*middle < val)
left = middle + 1;
else
right = middle;
}
return left;
}
答案 1 :(得分:3)
进行两次二进制搜索:
在第一次搜索中,如果中间元素等于所搜索的元素,则选择左半部分。
在第二次搜索中,如果中间元素等于所搜索的元素,则选择右半部分。
Java中的示例代码:
class Test {
public static int findElem(int[] arr, int elem, int l, int h,boolean first) {
if (h - l <= 1)
return first ? (arr[l] == elem ? l : h) : (arr[h] == elem ? h : l);
int m = l + (h - l) / 2;
if (arr[m] < elem || (arr[m] == elem && !first))
return findElem(arr, elem, m, h, first);
return findElem(arr, elem, l, m, first);
}
public static int findElem(int[] arr, int elem, boolean first) {
return findElem(arr, elem, 0, arr.length, first);
}
public static void main(String[] args) {
int[] arr = { 0, 1, 2, 2, 2, 3, 3, 4, 4, 5 };
int elem = 2;
System.out.println("First index: " + findElem(arr, elem, true));
System.out.println("Last index : " + findElem(arr, elem, false));
}
}
答案 2 :(得分:1)
您应该二进制搜索匹配序列的第一个和最后一个元素。如果您使用的是C ++,那么STL中有lower_bound
和upper_bound
等功能可以让您这样做。否则,这是对算法的简单修改。
或者,您可以使用3个二进制搜索:
然而,能够做到最后2意味着你已经实现了第一个解决方案(通过找到下限/上限)
答案 3 :(得分:0)
如果要多次执行此操作,可以创建一个哈希表,其中元素值为键,第一个和最后一个元素的索引为值。
读取数据以创建哈希表是O(n)操作,但是查找索引接近于O(1)操作。
答案 4 :(得分:0)
假设您有a
个n
个T
元素的排序数组x
。然后对于某个元素T* ub = upper_bound( a, a + n, x );
int answer = ub - lower_bound( a, ub, x );
,您可以按如下方式找到它的重复次数:
O(logn)
复杂性显然是x
。当所有元素相同或a
中没有元素upper_bound
时,a+n
将返回lower_bound
,2 * logn
将在整个时间间隔内工作,将针对这些最糟糕的情况进行{{1}}次迭代。