[LeetCode] Search for a Range

Given a sorted array of integers, find the starting and ending position of a given target value.

Your algorithm's runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

二分查找很简单,可是二分查找真的很简单吗?考虑下面几个问题:

1. 二分查找target,返回任意找到的下标,没找到返回-1;

2.二分查找第一次出现target的下标,没找到返回-1;

3.二分查找最后一次出现target的下标,没找到返回-1;

4.二分查找数组中比target小的最大的数,不存在返回-1;

5.二分查找数组中比target大的最小的数,不存在返回-1.

如果能快速写出上面5个问题的代码,那么你已经基本掌握二分查找了。那么再来看这道题,对应的就是上面的问题2和问题3了。怎么处理这种问题呢?其实只要把复杂的问题简单化,我们就能很快找到其中的奥秘。那么不妨我们就考虑只有两个元素的情况,一般来说,我习惯让R = n - 1,这样M一定是两个元素中的第一个元素:

如果我们要找最左边的位置,那么当A[M]==target时,就应该固定L,改变R,也就是:

if(A[M] >= target) R = M - 1;

最后的L就是我们要找的;

反之,如果要找最右边的位置,那么就固定R,改变L,也就是:

if(A[M] <= target) L = M + 1;

最后的R就是我们要找的。

这样是不是就很清楚了呢?而对于4,5问,也是同样的道理,只对2,3问我们想到的分别是L,R,而4,5问我们要的是R,L,或者说是L-1,R+1。

 1 class Solution {
 2 public:
 3     int searchLeft(int A[], int n, int target) {
 4         int L = 0, R = n - 1, M;
 5         while (L <= R) {
 6             M = L + ((R - L) >> 1);
 7             if (A[M] >= target) R = M - 1;
 8             else L = M + 1;
 9         }
10         return (A[L] != target) ? -1 : L;
11     }
12     
13     int searchRight(int A[], int n, int target) {
14         int L = 0, R = n - 1, M;
15         while (L <= R) {
16             M = L + ((R - L ) >> 1);
17             if (A[M] <= target) L = M + 1;
18             else R = M - 1;
19         }
20         return (A[R] != target) ? -1 : R;
21     }
22     
23     vector<int> searchRange(int A[], int n, int target) {
24         vector<int> res(2);
25         res[0] = searchLeft(A, n, target);
26         res[1] = searchRight(A, n, target);
27         return res;
28     }
29 };

这里有个小问题,如果数组里没有target,且target比最小数还小或者比最大数还大,可能会出现下标访问越界,所以访问前要先判断一下返回的下标是不是在0~n-1之间。

posted @ 2015-03-27 13:44  Eason Liu  阅读(234)  评论(0编辑  收藏  举报