leetcode - [34. 在排序数组中查找元素的第一个和最后一个位置]
题目大意
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。
解题思路
- 给出一个有序数组
nums
和一个数target
,要求在数组中找到第一个和这个元素相等的元素下标,最后一个和这个元素相等的元素下标。 - 这一题是经典的二分搜索变种题。二分搜索有 4 大基础变种题:
- 查找第一个值等于给定值的元素
- 查找最后一个值等于给定值的元素
- 查找第一个大于等于给定值的元素
- 查找最后一个小于等于给定值的元素
这一题的解题思路可以分别利用变种 1 和变种 2 的解法就可以做出此题。或者用一次变种 1 的方法,然后循环往后找到最后一个与给定值相等的元素。不过后者这种方法可能会使时间复杂度下降到 O(n),因为有可能数组中 n 个元素都和给定元素相同。(4 大基础变种的实现见代码)
#include <iostream>
#include <vector>
using namespace std;
int binary_search(int A[], int low, int high, int key);
/*
* O(log n) 解决方案必须类似于二进制搜索。
*
* 所以,我们可以使用二分查找找到一个位置——`pos`
*
* 然后,我们可以继续使用二分查找在 A[0..pos-1] 和 A[pos+1..n] 中找到目标
*
* 下面的代码是不言自明的
*/
vector<int> searchRange(int A[], int n, int target)
{
int pos = binary_search(A,0,n-1,target);
vector<int> v;
int low = -1,high = -1;
if(pos >= 0)
{
low = high = pos;
int l = low;
do
{
low = l;
l = binary_search(A, 0 ,low - 1, target);
}while(l>=0);
int h = high;
do
{
high = h;
h = binary_search(A, high + 1, n - 1, target);
}while(h>=0);
}
v.push_back(low);
v.push_back(high);
return v;
}
int binary_search(int A[], int low, int high, int key)
{
while(low <= high)
{
int mid = low + (high - low)/2;
if(A[mid] == key)
{
return mid;
}
if(key > A[mid])
{
low = mid + 1;
}
if(key < A[mid])
{
high = mid - 1;
}
}
return -1;
}
void printVector(vector<int>& pt)
{
cout<<"{";
for(int j = 0; j<pt.size(); j++)
{
cout<<pt[j]<<" ";
}
cout<<"}"<<endl;
}
int main()
{
const int cnt = 6;
int a[cnt] = {5, 7, 7, 8, 8, 10};
vector<int> v;
v = searchRange(a, cnt, 8);
printVector(v);
int b[cnt] = {5, 5, 5, 8, 8, 10};
v = searchRange(b, cnt, 5);
printVector(v);
int c[cnt] = {5, 5, 5, 5, 5, 5};
v = searchRange(c ,cnt, 5);
printVector(v);
return 0;
}