视频链接 :
二分查找 红蓝染色法_哔哩哔哩_bilibili
在排序数组中查找元素的第一个和最后一个位置
链接 :
在排序数组中查找元素的第一个和最后一个位置
思想 :
暴力 :
在lc上,直接暴力枚举左端点和右端点也是能够通过的!
二分 :
题目要求在O(log n)的时间复杂度处理该问题,那么就要用到二分的思想了!
设l,r为要找的区间的左右端点
代码 :
1.暴力 (c++)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int n=nums.size();
int ans1=-1,ans2=-1;
int num=0;
if(n==0)
{
ans1=-1;
ans2=-1;
}
if(n==1){
if(nums[0]==target)
{
ans1=0;
ans2=0;
}
else{
ans1=-1;
ans2=-1;
}
}
if(n>=2)
{
for(int i=0;i<n;i++)
{
if(nums[i]==target)
num++;
}
if(num==0)
{
ans1=-1;
ans2=-1;
}
if(num==1)
{
for(int i=0;i<n;i++){
if(nums[i]==target)
{
ans1=i;
ans2=i;
}
}
}
if(num>=2)
{
for(int i=0;i<n;i++)
{
if(nums[i]==target)
{
ans1=i;
break;
}
}
for(int j=n-1;j>=0;j--)
{
if(nums[j]==target)
{
ans2=j;
break;
}
}
}
}
return {ans1,ans2};
}
};
2.二分(python)
# lower_bound 返回最小的满足 nums[i] >= target 的 i
# 如果数组为空,或者所有数都 < target,则返回 len(nums)
# 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]
# 闭区间写法
def lower_bound(nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1 # 闭区间 [left, right]
while left <= right: # 区间不为空
# 循环不变量:
# nums[left-1] < target
# nums[right+1] >= target
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 范围缩小到 [mid+1, right]
else:
right = mid - 1 # 范围缩小到 [left, mid-1]
return left # 或者 right+1
# 左闭右开区间写法
def lower_bound2(nums: List[int], target: int) -> int:
left = 0
right = len(nums) # 左闭右开区间 [left, right)
while left < right: # 区间不为空
# 循环不变量:
# nums[left-1] < target
# nums[right] >= target
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 范围缩小到 [mid+1, right)
else:
right = mid # 范围缩小到 [left, mid)
return left # 或者 right
# 开区间写法
def lower_bound3(nums: List[int], target: int) -> int:
left, right = -1, len(nums) # 开区间 (left, right)
while left + 1 < right: # 区间不为空
mid = (left + right) // 2
# 循环不变量:
# nums[left] < target
# nums[right] >= target
if nums[mid] < target:
left = mid # 范围缩小到 (mid, right)
else:
right = mid # 范围缩小到 (left, mid)
return right # 或者 left+1
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
start = lower_bound(nums, target) # 选择其中一种写法即可
if start == len(nums) or nums[start] != target:
return [-1, -1]
# 如果 start 存在,那么 end 必定存在
end = lower_bound(nums, target + 1) - 1
return [start, end]
3.二分(c++)
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// 情况一
if (leftBorder == -2 || rightBorder == -2) return {-1, -1};
// 情况三
if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1};
// 情况二
return {-1, -1};
}
private:
int getRightBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else { // 寻找右边界,nums[middle] == target的时候更新left
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
int getLeftBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
}
return leftBorder;
}
};