[算法题]在排序数组中查找元素的第一个和最后一个位置

题目链接: 在排序数组中查找元素的第一个和最后一个位置

二分查找求解, 但是普通版本的二分查找无法求解, 普通版本的二分查找每次根据中点的值与目标值进行区间划分, 但是该题数据为非递减顺序, 所以可能出现如下情况:

nums = [1, 2, 3, 3, 3, 4, 5, 6]

target = 3

此时普通版本就不好使了, 因为你能确定目标值在哪但不能确定左右端点在哪, 所以使用寻找左端点和右端点的二分查找:

1. 寻找左端点的二分查找

区间划分规则:

1) nums[m] < target : l = m + 1;

2) nums[m] >= target : r = m;

其中r = m是关键, 不能是r = m - 1, 因为r所在的位置可能是左端点, 所以不能排除该位置.

循环条件: l < r时继续, l == r时结束循环, 不能等于因为会出现死循环, 而且l == r时就是结果出现之时, 此时只需判断该位置的值是否等于目标值即可.

求中间值公式: m = l + (r - l) / 2, 不需要+1, +1会导致死循环, 当遍历区间只剩两个元素时, 可能出现如下情况:

如果此时是这种情况: nums[m] >= target : r = m, 那就死循环了, 而不+1就没问题.

2. 寻找右端点的二分查找

区间划分规则:

1) nums[m] <= target : l = m;

2) nums[m] > target : r = m - 1;

其中l = m是关键, 不能是l = m + 1, 因为l所在的位置可能是右端点, 所以不能排除该位置.

循环条件: l < r时继续, l == r时结束循环, 不能等于因为会出现死循环, 而且l == r时就是结果出现之时, 此时只需判断该位置的值是否等于目标值即可.

求中间值公式: m = l + (r - l + 1) / 2, 一定要+1, 不+1会导致死循环, 当遍历区间只剩两个元素时, 可能出现如下情况:

如果此时是这种情况: nums[m] <= target : l = m, 那就死循环了, 而+1就没问题.

寻找左端点/右端点版本的二分查找注意事项:

1. 循环条件 while(left < right).

2. 寻找左端点时求中点公式为left + (right - left) / 2, 寻找右端点时求中点公式为left + (right - left + 1) / 2.

本体题解思路: 先使用寻找左端点版本的二分查找找出左端点, 再使用寻找右端点版本的二分查找找出右端点即可.

题解代码:

class Solution 
{
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        if(nums.empty()) return {-1, -1};
        vector<int> res(2, -1);
        //找左端点
        int left = 0;
        int right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] < target) left = mid + 1;
            else if(nums[mid] >= target) right = mid;
        }
        if(nums[left] == target) res[0] = left;
        //找右端点
        left = 0;
        right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left + 1) / 2;
            if(nums[mid] <= target) left = mid;
            else if(nums[mid] > target) right = mid - 1;
        }
        if(nums[left] == target) res[1] = left;
        return res;
    }
};

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值