主要内容 #
- 第一个和最后一个位置
- 求解思路
- 参考代码
1. 第一个和最后一个位置 #
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例1
输入:nums = [5,7,7,8,8,10], target = 8 输出:[3,4]
示例2
输入:nums = [5,7,7,8,8,10], target = 6 输出:[-1,-1]
示例3
输入:nums = [5,7,7,8,8,10], target = 6 输出:[-1,-1]
2. 求解思路 #
1. 由于题目告知这个数组是升序排列的,所以可以通过二分查找的方法来解答此题;
2. 如何查找元素的第一个位置?利用二分查找找到数组中某元素值等于目标值 target 时,不像二分查找的模板那样立即返回(数组中有多个元素值等于 target),而是通过缩小查找区间的上边界 high (令high= mid – 1),不断向 mid 的左侧收缩,最后达到锁定左边界(元素的第一个位置)的目的;
3. 如何查找元素的最后一个位置?同查找元素的第一个位置类似,在查找到数组中某元素值等于目标值 target 时,不立即返回,通过增大查找区间的下边界 low (令low= mid + 1),不断向 mid 的右侧收缩,最后达到锁定右边界(元素的最后一个位置)的目的;
4. 没有找到,则直接返回 [-1,-1]。
以 nums = [5,7,7,8,8,10], target = 8 为栗子,通过下图来找出目标值 8 在数组中出现的第一个和最后一个位置。如下图示:
查找 8 出现的第一个位置:
由于此时 nums[mid] = 7 < target = 8,所以需要在右半区间 (mid, high] 中查找,即 low = mid + 1 = 3, mid = (high + low) /2 = 4。

此时nums[mid] = 8 == target = 8, 按照解题思路方法一中 2 的描述,找到数组中元素值等于目标值 target 时,不立即返回,而是缩小查找区间的上边界 high (令 high = mid – 1 = 3),不断向 mid 的左侧收缩, mid = (high + low) / 2 = 3。

继续缩小查找区间的上边界 high。

由于此时 high < low,代表查找 8 在数组中出现的第一个位置结束。

查找 8 出现的最后一个位置:
前两步跟查找 8 出现的第一个位置一样。
此时nums[mid] = 8 == target = 8, 按照解题思路方法一中 3 的描述,找到数组中元素值等于目标值 target 时,不立即返回,而是增大查找区间的下边界 low (令 low = mid + 1 = 5),不断向 mid 的右侧收缩,mid = (high + low) / 2 = 5。

此时,nums[mid] = 10 > target = 8,high = mid – 1 = 4 。

由于此时 high = 4 < low = 5,结束查找,代表查找 8 在数组中出现的最后一个位置结束。

3. 参考代码 #
int GetTargetPosition(int* nums, int numsSize, int target, int locFlag) {
int last = -1;
int low = 0, high = numsSize - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (nums[mid] < target) {
low = mid + 1;
} else if (nums[mid] > target) {
high = mid - 1;
} else if (nums[mid] == target) {
last = mid;
if (locFlag == 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
}
return last ;
}
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
int* res = (int *)malloc(2 * sizeof(int));
memset(res, -1, 2 * sizeof(int));
*returnSize = 2;
if (nums == NULL || numsSize < 1) {
return res;
}
/* 通过 locFlag 标志区分查找的元素的位置在一个还是最后一个 */
int firstPos = GetTargetPosition(nums, numsSize, target, 0);
int lastPos = GetTargetPosition(nums, numsSize, target, 1);
/* 数组中没有目标元素 */
if (firstPos == -1 || lastPos == -1) {
return res;
}
res[0] = firstPos;
res[1] = lastPos;
return res;
}