V
已排序V.size() = N
searchNumOccurrence(V, k, 0, N-1)
功能代码:
int searchNumOccurrence(vector<int> &V, int k, int start, int end) {
if (start > end) return 0;
int mid = (start + end) / 2;
if (V[mid] < k) return searchNumOccurrence(V, k, mid + 1, end);
if (V[mid] > k) return searchNumOccurrence(V, k, start, mid - 1);
return searchNumOccurrence(V, k, start, mid - 1) +
1 + searchNumOccurrence(V,k, mid + 1, end);
}
答案 0 :(得分:2)
好的,我们来看看你做了什么。首先,你采取中间指数。然后检查数字是大于还是小V[mid]
,如果不是,则会增加计数器,并通过mid
1
移动(searchNumOccurrence(V, k, start, mid - 1))
位置来左右检查; searchNumOccurrence(V,k, mid + 1, end)
。
问题在于mid
向下移动1.让我们说,你有这个数组:
2 2 2 2 2 2 2 2 2 2 2 2 2 2
这意味着,您必须通过迭代1检查每个索引。这是O(n)
,因此您的算法为O(n)
。
现在,有一种更好的方法。由于您已对数组进行排序,因此不要查找每个匹配项,在给定数组中搜索该数字的子集,更精确,该数字的子集的起始和结束索引。这样,您基本上可以使用以下规则搜索2个索引:
index1
位于V[index1] = k
,但如果index1 > 0
则为V[index1 - 1] < k
index2
在V[index2] = k
的位置,但如果index2 < end - 1
则为V[index2 + 1] > k
搜索这两个索引为O(log_2(n))
(O(lgn)
),结果为numberOfOccurrences = index2 - index1 + 1
。
编辑:首先,搜索左侧索引。如果数组中不存在k
,请返回0
以获取功能,并且您不需要选择正确的索引(感谢@ craig-young)。如果找到左索引,那么您知道您将找到正确的(当且仅当左索引存在时存在),但在子集[index1, end)
下搜索。
答案 1 :(得分:0)
最糟糕的情况是递归函数必须迭代所有元素。
即如果|V|=4
,k=1
1 1 1 1
1 1 | 1 1
1 | 1
1
上面树的高度为O(log_2(|V|))
,元素数量为O(|V|)
。因此w.r.t | V |,最多会有O(| V | log_2(| V |))递归调用,其中| V |是V的大小。
自从我采用算法以来已经有一段时间了,所以如果有任何人能够让我知道我是不是错了。
答案 2 :(得分:0)
如果数组中的所有值都相同怎么办?程序运行多长时间?首先看起来程序是O(log N)。 但是,最后一个案例
return searchNumOccurrence(V, k, start, mid - 1) + 1 + searchNumOccurrence(V, k, mid + 1, end);
是瓶颈的一步。 假设数组中的所有值都相同,我们得到以下关系:
T(N) = 2 * T(N/2) + constant
= 4 * T(N/4) + constant ( 2 * constant = another constant )
= 8 * T(N/8) + constant
...
= N * T(N/N) + constant
= N + constant
= O(N)