问题描述:
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]
.
释义:数组有序, 非递减顺序, 算法时间复杂度要求O(log n), 找到指定target在数组中的下标区间, 数组起始位置为0, 数组数量 n。
问题分析:
1. 二分法保证算法复杂度为 O(log n), 利用二分法分别寻找起始位置left和终止位置right;
2. 确定边界条件和异常情况;
3. 考虑边界条件:A[0]==target && A[n-1] == target 与 A[0]>target || target>A[n-1] 与 n<=0 等情况进行处理;
实现:
采用二分法方式进行处理:
/*
* @biref: using binary search for achieving the algorithm's runtime complexity be in the order of O(log n)
* @authour: zhangjinxing jinxingbay@163.com
* @time: 2015 01 04 09 40
* @edition: 3.0
* @ notation backups
*/
class Solution {
public:
vector<int> searchRange(int A[], int n, int target) {
if (target == A[0] && target == A[n-1]) {
// special case: the whole sortd array is a combination of target A[] = {target, target , ..., target}
// return the whole range [0, n-1]
vector<int> ret{0, n-1};
return ret;
}
// find the left bound of the range
const int left = searchLeftBound(A, 0, n-1, target);
// find the right bound of the range
const int right = searchRightBound(A, 0, n-1, target);
// return the range of the combination of {target}
vector<int> ret{left, right};
return ret;
}
private:
// @brief: search the left bound of the range in the array
// @authour: zhangjinxing thoughts derives from the dream at 2015 01 04
// @time: 2015 0104
// @parameter: const int A[] -- array
// const int ibeg, begin index of the array A[] to be find
// const int iend, end index of the array A[]
// const int target, target combination number
int searchLeftBound(const int A[], const int ibeg, const int iend, const int target) {
int left = -1;
// case 1
/*if (ibeg > iend) {// out of the range
return left;
}
*/
// case 2
if (ibeg == iend) {// only one number to be search
if (target == A[ibeg]) {// if the number is equal to the target, return the index
left = ibeg;// left = iend;
}
return left;
}
// case 3
const int n = iend - ibeg + 1;// get the total numbers of the array
if (n <= 0) {// the array is zero or out of the range, case1 is the subset here
return left;
}
// case 4
if (target < A[ibeg] || target > A[iend]) {// the target is not contained in the array
return left;// left === -1
}
// case 5
const int imid =ibeg + (iend - ibeg)/2;// middle index of the array A sized by n
if (A[imid] > target) {// left bound must in the range A[ibeg, imid-1], search it
left = searchLeftBound(A, ibeg, imid-1, target);
}
if (A[imid] < target) {// left bound must in the range A[imid+1, iend], search it
left = searchLeftBound(A, imid+1, iend, target);
}
if (A[imid] == target) {// in the range A[ibeg, imid]
left = searchLeftBound(A, ibeg, imid, target);
}
return left;
}
int searchRightBound(const int A[], const int ibeg, const int iend, const int target) {
int right = -1;
// case 1
/*if (ibeg > iend) {// out of range
return right;
}*/
// case 2
if (ibeg == iend ) {
if (target == A[ibeg]) {// begin == end, only one number
right = iend;// right = ibeg
}
return right;
}
// case 3
const int n = iend - ibeg + 1;// get the total numbers of the array
if (n <= 0) {// the array is zero or out of the range, case1 is the subset here
return right;
}
// case 4
if (target < A[ibeg] || target > A[iend]) {// the target is not contained in the array
return right;// right === -1
}
// case 5
if (1 == (iend - ibeg)) {// ibeg + 1 == iend, two numbers here
if (A[iend] == target) {// if the *end === target, return iend
right = iend;
} else if (A[ibeg] == target){// if the*end != target && *beg === target, return ibeg
right = ibeg;
}
return right;
}
// case 6
const int imid = ibeg + (iend - ibeg)/2;// middle index of the array A sized by n, lower to int
if (A[imid] > target) {// right bound must in the range A[ibeg, imid-1], search it
right = searchRightBound(A, ibeg, imid-1, target);
}
if (A[imid] < target) {// right bound must in the range A[imid+1, iend], search it
right = searchRightBound(A, imid+1, iend, target);
}
if (A[imid] == target) {// right bound maybe in the range A[imid, iend] or A[imid+1]
// case 6.1: {target, x, x, y, ...} --- right = imid
// case 6.2: {target, ..., target, ...} --- right = r_uper
right = searchRightBound(A,imid, iend, target);// may return imid, or r_uper
const int r_uper = searchRightBound(A,imid+1, iend, target);// in first case, return -1; in second case, return last index
if (-1 != r_uper) {
right = r_uper;
}
}
return right;
}
};分析
注意left 和 right 的区别之处,以及产生的原因。
i. searchLeftBound中,通过比较A[imid] 与 target, 当A[imid]>target时,left 肯定在[ibeg, imid-1]区间内;当A[imid]<target, left在[imid+1, iend]区间内;当A[imid]== target,left在[imid, iend]区间内;
ii. searchRightBound中,同样分析三种情况,并对相等情况进行特殊处理;
注意其他特殊情况,并进行处理,以及特殊情况处理的顺序问题。
总结
i. consider special cases completely, using the whole given conditions;
ii. build the bug-free coding fragment is difficult, to be there, I must do exercises, coding & thinking;
iii. run the codes in you heart under special cases first;
iv. special cases comes first and just "code" it.
-----One "Acceptance" a day, keep my mind awake.-----noted by bayingbf-----2015.01.04-----