题目大意
在一个有序数组中查找给定的一个数,给出它出现的最左与最右的位置,要求时间复杂度是O(logn)
分析
根据时间复杂度,很明显能看出来要用基于二分的方法,将二分查找稍微修改一下就好,传统的二分查找当我们在中间位置找到了target的时候会直接返回,如果要查找最左出现的位置,可以判定一下nums[mid - 1],如果等于target的话,就将right改为mid - 1,继续迭代,同理可以求最右出现的位置。
源代码
int search1(vector<int>& nums, int target) { //搜索最左出现的位置
int left = 0, right = nums.size() - 1, mid;
if(nums.size() == 0) {
return -1;
}
while(left <= right) {
mid = (left + right) >> 1;
if(nums[mid] == target) {
if(mid - 1 >= 0 && nums[mid - 1] == target) {
right = mid - 1; //如果左边仍然有target,则继续向左边移动元素
continue;
} else {
break;
}
}
if(nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
if(nums[mid] == target) { //判断最终是否存在target
return mid;
} else {
return -1;
}
}
int search2(vector<int>& nums, int target) { //搜索最右出现的位置
int left = 0, right = nums.size() - 1, mid;
while(left <= right) {
mid = (left + right) >> 1;
if(nums[mid] == target) {
if(mid + 1 <= nums.size() - 1 && nums[mid + 1] == target) {
left = mid + 1;
continue;
} else {
break;
}
}
if(nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
if(nums[mid] == target) {
return mid;
} else {
return -1;
}
}
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> rs;
int index1 = search1(nums, target);
if(index1 == -1) { //不存在则直接返回-1
rs.push_back(-1);
rs.push_back(-1);
return rs;
}
int index2 = search2(nums, target);
rs.push_back(index1);
rs.push_back(index2);
return rs;
}
注意一点实现上的细节,如果nums中不存在元素的话,那么最终二分查找的while循环将会以left>right的方式跳出,注意到除非中间元素为target,否则left或right将会持续变化,left=right的情况不会造成死循环。