二分搜索适合既有下界也有上界,对于只知道一边的界情况,可以用倍增搜索法
int search(vector<int> A, int x) {
for (int i = 0; A[i] <= x;) {
if (A[i] == x) return i;
if (i + 1 == A.size() || A[i + 1] > x) return -1;
for (int k = 1; i + k < A.size() && A[i + k] <= x; k += k)
i += k;
}
return -1;
}
类似问题有用除法的定义(只用加法)实现除法。
循环不变式:如果数组中存在x, 它必然在大于等于位置i 的地方
算法框架:
1)如果起点处i的值A[i] > x,否则说明这个范围内不存在x, 返回-1
2)如果起点A[i]==x,找到,返回位置i
否则就是A[i] < x:
这时候如果 A[i + 1] > x, 也说明不存在,返回-1
否则进行倍增查找,当i跳某个步长k后的值A[i+k] 大于x ,本轮倍增结束,一直保持着不变式 A[i] <= x ,主循环下一轮相当于是解决一个相同的问题,只不过i已经推进了很多,离目标近了一些。用递归看更清晰:
int search(vector<int> &A, int i, int x) {
if (A[i] > x) return -1;
if (A[i] == x) return i;
if (i + 1 == A.size() || A[i + 1] > x) return -1;
for (int k = 1; i + k < A.size() && A[i + k] <= x; i += k, k += k);
return search(A, i, x);
}
另一种更通用的模板:
int search(vector<int> A, int x) {
int i = -1; //i is the farest position currently searched
for (;;) {
int k = 1;
for (; i + k < A.size() && A[i + k] <= x; k += k) {
i += k;
}
if (i >= 0 && A[i] == x) return i;
if (k == 1) return -1;
}
}
bool isPowerOfThree(int n) {
int x = 1; //closed position that not exceed
for (;;) {
int step = 3;
for (; n / step >= x; step *= step) {
x *= step;
}//exit: could not add the current step
if (x == n) return true;
if (step == 3) return false; //could not go one step further, or will exceed
}
}