1 题目及要求
1.1 题目描述
二分查找相关问题一直是面试中的热门问题之一。有序数组的二分查找问题大致就分为那么8类(参考,作者:LightGHLi连接:https://www.zhihu.com/question/36132386/answer/105595067):
(1)对于不下降序列a,求最小的i,使得a[i]= key;
(2)对于不下降序列a,求最大的i,使得a[i]= key;
(3)对于不下降序列a,求最小的i,使得a[i]> key;
(4)对于不下降序列a,求最大的i,使得a[i]< key;
(5)对于不上升序列a,求最小的i,使得a[i]= key;
(6)对于不上升序列a,求最大的i,使得a[i]= key;
(7)对于不上升序列a,求最小的i,使得a[i]< key;
(8)对于不上升序列a,求最大的i,使得a[i]> key。
而如果对于每个不同的类型都去具体实现,则会涉及二分向上或者向下取整,区间的开闭,以及判断条件的改变等。情况太多,记起来特别麻烦还特容易混淆。
下面针对不下降序列,只用一个二分查找去实现(1)到(4)的不同功能。其中当存在i时则返回i,否则返回-1。
首先实现一个 intbinarySearch(int *v, int vn, int k)的函数,v为输入数组(不下降序列),n为其长度,k为待查找数值。该函数的功能为返回最小i,使得k<=v[i](也即k<=v[i] 且 v[i-1]<k);当输入为空时返回-1。注意该函数有坑能返回数组的长度,也即尾后下标。
下面利用该函数实现(1)到(4)
(1) int bs1(int*v, int vn, int k)
调用 index = binarySearch(v,vn,k),则有v[index-1]<k <=v[index]。因此当v[index]==k时,index就是所求;否则不存在。
(2) intbs2(int *v, int vn, int k)
调用 index = binarySearch(v,vn,k+1)-1,则有k+1 <=v[index+1]且 v[index] < k+1,
也即k < v[index+1] 且 v[index]<=k。因此当v[index]==k时,index就是所求;否则不存在。
(3) intbs3(int *v, int vn, int k)
调用 index = binarySearch(v,vn,k+1),则有k+1 <=v[index]且 v[index-1] < k+1,
也即v[index-1]<= k < v[index]。index即为所求。(返回尾后下标时特别处理)。
(4)int bs4(int*v, int vn, int k)
调用 index = binarySearch(v,vn,k)-1,则有k <=v[index+1]且 v[index] < k,
也即v[index]< k <= v[index+1]。index即为所求。index即为所求。
2 解答
2.1 代码
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int binarySearch(int *v, int vn, int k) {
if (!v || vn < 1) return -1;
int lo(0), up(vn), mid;
while (lo < up) {
mid = lo + ((up - lo) >> 1);
if (v[mid] < k) lo = mid + 1;
else up = mid;
}
return lo;
}
int bs1(int *v, int vn, int k) {
if (!v || vn < 1) return -1;
int index = binarySearch(v, vn, k);
return v[index] == k ? index : -1;
}
int bs2(int *v, int vn, int k) {
if (!v || vn < 1) return -1;
int index = binarySearch(v, vn, k + 1) - 1;
return v[index] == k ? index : -1;
}
int bs3(int *v, int vn, int k) {
if (!v || vn < 1) return -1;
int index = binarySearch(v, vn, k + 1);
return index == vn ? -1 : index;
}
int bs4(int *v, int vn, int k) {
if (!v || vn < 1) return -1;
return binarySearch(v, vn, k) - 1;
}
int main() {
int a[] = { 1,2,2,2,4,4,5 }, n = sizeof(a) / sizeof(a[0]);
cout << "输入数组:";
for (int k1(0);k1 < n;++k1) cout << setw(8) << a[k1] << ' ';
cout << endl << "数组下标:";
for (int k1(0);k1 < n;++k1) cout << setw(8) << k1 << ' ';
cout << endl << "查找数值" << " bs1 bs2 bs3 bs4" << endl;
for (int k1(1);k1 < n+1;++k1) {
cout << setw(8) << k1 << setw(8) << bs1(a, n, k1)
<< setw(8) << bs2(a, n, k1) << setw(8) << bs3(a, n, k1)
<< setw(8) << bs4(a, n, k1) << endl;
}
return 0;
}