我在定义查找二进制搜索的第一个元素的不变性时遇到问题。 (我有一个排序数组a,我想找到等于某个数字q的第一个元素,如果不存在则返回-1)
首先,我暂时设置此不变式。
我的不变性
“总是a [l] <= q以及a [r]> q” ==>“总是l <= ind以及> ind”。
根据我的不变式,我编写了以下代码:
int l=0,r=n;
while(l<r){
int mid=(r+l)/2;
if(a[mid]==q){
r=mid+1;
}
else{
if(a[mid]>q){
r=mid;
}else if(a[mid]<q) l=mid+1;
}
}
return l;
但是有一个问题,if(a[mid]==q)
然后我必须选择一个不违反我的不变式的r
。
如果我选择mid-1
,则会违反它,因为a[r]
将是<= q
。
我必须遍历索引,直到找到索引a[i]>q
的索引I,然后将r
设置为该索引。 (r = i)==>但是如果我这样做不是O(log n)
我已经看到一些实现lower_bound
的代码,将if(a[mid]==q)
的{{1}}设置为r
,但是我认为它们违反了它们的不变性,但是它们的代码正确并返回正确的值。
喜欢此代码:
mid
首先,不变式就像我的不变式(1- int l = 0;
2- int r = n; // Not n - 1
3- while (l < r) {
4- int mid = (l + r) / 2;
5- if (q <= a[mid]) {
6- r = mid;
7- } else {
8- l = mid + 1;
9- }
10- }
11- return l;
在i
的范围内,但在第5行中考虑[l,r)
则显然违反了,因为其({{1 }},因为if(q==a[mid])
相等,并且可能是第一个出现)。
我是对的还是我对不变性没有正确的理解概念?
答案 0 :(得分:0)
假设我们有一个序列
..., <q, <q, <q, q, q, ..., q, q, >q, >q, >q, ...
^ (*)
其中<q
(>q
)代表任何元素< q
(> q
)。我们想找到点(*)。
我们有两个指针left < right
。我们如何使用它们来区分这一点?答案很简单:left
应该指向最后一个<q
元素,right
应该指向第一个q
元素:
..., <q, <q, <q, q, q, ..., q, q, >q, >q, >q, ...
^ right
^ left
不变式为:*left < q
和*right >= q
。
您建议的不变式*left <= q
和*right > q
对应于该序列中的最后一个元素:
..., <q, <q, <q, q, q, ..., q, q, >q, >q, >q, ...
^ right
^ left
一些有用的参考文献: