给一个按照升序排序的非负整数数组。这个数组很大以至于你只能通过固定的接口 ArrayReader.get(k)
来访问第k个数(或者C++里是ArrayReader->get(k)),并且你也没有办法得知这个数组有多大。
找到给出的整数target第一次出现的位置。你的算法需要在O(logk)的时间复杂度内完成,k为target第一次出现的位置的下标。
如果找不到target,返回-1。
样例
样例 1:
输入: [1, 3, 6, 9, 21, ...], target = 3
输出: 1
样例 2:
输入: [1, 3, 6, 9, 21, ...], target = 4
输出: -1
挑战
O(logn)的时间复杂度,n是target第一次出现的下标。
注意事项
如果你访问了一个不可访问的下标(比如越界),ArrayReader 会返回2147483647
。
解题思路:
显然是二分查找,但是此题没有右边界,需要我们先确定右边界后再二分查找。
确定右边界可以采用倍增法,初始右边界为1, 如果右边界的数小于 target, 就将其倍增, 直到右边界不小于target. 这时就可以二分查找了.
注意: 越界访问是没有关系的, 因为这个ArrayReader在越界访问时, 返回 INT_MAX, 一定不小于 target. 而即使是返回 -1 之类的数值, 我们也可以加一个判断搞定.
/**
* Definition of ArrayReader:
*
* public class ArrayReader {
* public int get(int index) {
* // return the number on given index,
* // return 2147483647 if the index is invalid.
* }
* };
*/
public class Solution {
/*
* @param reader: An instance of ArrayReader.
* @param target: An integer
* @return: An integer which is the first index of target.
*/
public int searchBigSortedArray(ArrayReader reader, int target) {
// write your code here
int l = 0;
int r = 1;
while (reader.get(r) < target) // 越界返回INT_MAX, 必然大于target, 所以没有关系
r <<= 1;
while(l < r){
int mid = (r+l)>>1;
if(reader.get(mid) >= target)
r = mid;
else
l = mid + 1;
}
if(reader.get(l) != target)
return -1;
return l;
}
}