2/3 寻找目标出现的初始or最后位置(First Position of Target/Last Position of Target)
1 题目
寻找目标出现的初始位置(First Position of Target)
lintcode:题号——14,难度——easy
2 描述
给定一个排序的整数数组(升序)和一个要查找的整数 target,用O(log n)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1。
样例:
输入:数组 = [1,4,4,5,7,7,8,9,9,10], target = 4
输出:1
3 思路
从头开始遍历需要的时间复杂度是O(n),要求在O(log n)的时间内完成,可以用二分法解决。
- 找到中间位置的元素;
- 与目标元素比较,确定目标元素所在的区间,缩小目标区间;
- 重复以上操作,直到找到或者结束。
与之前的经典二分搜索[1]大致相同,可以套用经典二分搜索的模版,需要注意的差异如下:
- 循环中与目标元素的比较在“>”和“==”时候的处理,都是抛掉右边的部分;
- 跳出循环之后,对剩下的两个元素的检查顺序是从左到右。
3.2 图解
graph TD
A[有序数组'1, 4, 4, 5, 7, 7, 8, 9, 9, 10' 目标元素'4'] -- 中间位置元素'7',大于目标元素'4' --> B
A --> A1[/抛掉'7, 8, 9, 9, 10'/]
B[缩小区间至'1, 4, 4, 5, 7'] -- 中间位置元素'4',小于等于目标元素'4' --> C
B --> B1[/抛掉'5, 7'/]
C[缩小区间至'1, 4, 4'] -- 中间位置元素'4',小于等于目标元素'4' --> D
D[缩小区间至'1, 4'] -- 在头尾元素中依次寻找目标元素 --> E
E(找到目标元素'4')
3.2 时间复杂度
算法的时间复杂度为O(log n)
3.3 空间复杂度
算法的空间复杂度为O(1)
4 源码
C++:
/**
* @param nums: 有序数组
* @param target: 目标元素的值
* @return: 目标元素在有序数组中的初始位置(下标序号)
*/
int binarySearch(vector<int> &nums, int target) {
// write your code here
if (nums.empty())
{
return -1;
}
int start = 0;
int end = nums.size() - 1;
int mid = 0;
while (start + 1 < end)
{
mid = start + (end - start) / 2;
if (nums.at(mid) >= target) // 大于和等于的情况处理方式相同
{
end = mid;
}
else
{
start = mid;
}
}
if (nums.at(start) == target) // 先判断左边的是否是目标元素
{
return start;
}
if (nums.at(end) == target)
{
return end;
}
return -1;
}
5 相同类型问题
题目:
寻找目标出现的最后位置(Last Position of Target)
lintcode:题号——458,难度——easy
C++版本:
/**
* @param nums: 有序数组
* @param target: 目标元素的值
* @return: 目标元素在有序数组中的最后位置(下标序号)
*/
int lastPosition(vector<int> &nums, int target) {
// write your code here
if (nums.empty())
{
return -1;
}
int start = 0;
int end = nums.size() - 1;
int mid = 0;
while (start + 1 < end)
{
mid = start + (end - start) / 2;
if (nums.at(mid) <= target)
{
start = mid;
}
else
{
end = mid;
}
}
if (nums.at(end) == target)
{
return end;
}
if (nums.at(start) == target)
{
return start;
}
return -1;
}

浙公网安备 33010602011771号