查找有序数组某元素首尾位置
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
给你一个按照非递减顺序排列的整数数组
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 = [], target = 0 输出:[-1,-1]提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
是一个非递减数组-109 <= target <= 109
思路
二分法,弄两次二分,分别查找该元素第一次出现的位置和最后一次出现的位置。以元素第一次出现为例,必须是数组中元素和寻找的对象元素相等的时候才可以寻找,而且第一次出现的时候应该是右端点逐渐缩小范围的时候,所以代码如下:
int findleft(vector<int>& nums, int target)
{
int l=0;
int r=nums.size()-1;
int getleft=-2;
while(l<=r)
{
int mid=l+(r-l)/2;
if(nums[mid]>=target)
{
r=mid-1;
getleft=r;
}
else
l=mid+1;
}
return getleft;
}
认识两个内置函数
lower_bound(nums.begin(), nums.end(),target); // 返回第一个大于等于target的位置
upper_bound(nums.begin(), nums.end(),target); // 返回第一个大于target的位置
总代码
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int getright= findright(nums, target);
int getleft= findleft(nums, target);
if (getleft == -2 || getright == -2) return {-1, -1};
// 情况三
if (getright- getleft > 1) return {getleft + 1, getright - 1};
// 情况二
return {-1, -1};
}
int findleft(vector<int>& nums, int target)
{
int l=0;
int r=nums.size()-1;
int getleft=-2;
while(l<=r)
{
int mid=l+(r-l)/2;
if(nums[mid]>=target)
{
r=mid-1;
getleft=r;
}
else
l=mid+1;
}
return getleft;
}
int findright(vector<int>& nums, int target)
{
int l=0;
int r=nums.size()-1;
int getright=-2;
while(l<=r)
{
int mid=l+(r-l)/2;
if(nums[mid]>target)
r=mid-1;
else
{
l=mid+1;
getright=l;
}
}
return getright;
}
};
x的平方根
给你一个非负整数
x
,计算并返回x
的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如
pow(x, 0.5)
或者x ** 0.5
。
代码
class Solution {
public:
int mySqrt(int x) {
int l=0;
int r=x;
int ans=-1;
while(l<=r)
{
int mid=l+(r-l)/2;
if((long long)mid*mid<=x)
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
return ans;
}
};
类似变形题
代码
class Solution {
public:
bool isPerfectSquare(int x) {
int l=0;
int r=x;
int ans=-1;
while(l<=r)
{
int mid=l+(r-l)/2;
if((long long)mid*mid<x&&(long long)mid*mid>x)//先判断不是整数的情况
{
return false;
}
if((long long)mid*mid==x)//再判断相等的情况
{
return true;
}
if((long long)mid*mid<x)//二分思路
{
l=mid+1;
}
else
r=mid-1;
}
return false;
}
};
总结:
1.可以适当多增加一个变量,这样思考更容易