【C/C++】在排序数组中查找元素的第一个和最后一个位置(leetcode T34)

核心考点:法一 双指针法;法二 二分查找法 

题目描述:

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。(示例见文末)

答案详解:

方法一:双指针法

vector searchRange(vector& nums, int target) {
    vector res = {-1, -1}; // 初始化结果数组,默认值为[-1, -1]
    int slow = -1, fast = 0, l = nums.size(); // slow记录最后一次出现目标值的位置,fast用于遍历
    int flag = 1; // 标记是否是第一次找到目标值
    while (fast < l) { // 遍历整个数组
        if (nums[fast] == target) { // 如果当前元素等于目标值
            slow = fast; // 更新最后一次出现目标值的位置
            if (flag) { // 如果是第一次找到
                flag = 0; // 取消第一次标记
                res[0] = fast; // 更新目标值的起始位置
            }
        }
        fast++; // 移动指针
    }
    res[1] = slow; // 记录目标值的结束位置
    return res; // 返回结果
}
  1. 定义两个指针:

    • fast 指针用于遍历数组,找到所有等于目标值的位置。

    • slow 指针记录最后一个等于目标值的位置。

  2. 如果找到目标值,且是第一次找到,则将 res[0] 设为当前索引。

  3. 每次找到目标值,都更新 slow

  4. 遍历结束后,slow 即为最后一个目标值的位置,存入 res[1]

  5. 如果遍历完整个数组仍未找到目标值,返回 [-1, -1]

时间复杂度:O(n)
空间复杂度:O(1)

方法二:二分查找法

vector searchRange(vector& nums, int target) {
    vector res = {-1, -1}; // 初始化结果数组,默认值为[-1, -1]
    int len = nums.size(); // 获取数组长度
    if (!len) // 如果数组为空,直接返回结果
        return res;
    
    int l = -1, r = nums.size();
    // 第一次二分查找,找到目标值的起始位置
    while (l + 1 != r) { // 通过二分法缩小搜索范围
        int m = (l + r) >> 1; // 取中间值
        if (nums[m] >= target) r = m; // 如果中位数大于等于目标值,缩小右边界
        if (nums[m] < target) l = m; // 如果中位数小于目标值,缩小左边界
    }
    if (r < len && nums[r] == target) // 如果找到目标值,更新起始位置
        res[0] = r;
    
    l = -1, r = nums.size();
    // 第二次二分查找,找到目标值的结束位置
    while (l + 1 != r) {
        int m = (l + r) >> 1;
        if (nums[m] > target) r = m; // 如果中位数大于目标值,缩小右边界
        if (nums[m] <= target) l = m; // 如果中位数小于等于目标值,缩小左边界
    }
    if (l >= 0 && nums[l] == target) // 如果找到目标值,更新结束位置
        res[1] = l;
    
    return res; // 返回结果
}
  1. 利用二分查找分别查找目标值的起始位置和结束位置。

  2. 第一次二分查找:

    • 如果当前中位数大于等于目标值,缩小右边界。

    • 如果当前中位数小于目标值,缩小左边界。

    • 最终右边界即为第一个目标值的位置。

  3. 第二次二分查找:

    • 如果当前中位数大于目标值,缩小右边界。

    • 如果当前中位数小于等于目标值,缩小左边界。

    • 最终左边界即为最后一个目标值的位置。

  4. 通过两次二分查找,精确找到目标值的区间。

时间复杂度:O(log n)
空间复杂度:O(1)

你可能感兴趣的:(c语言,c++,leetcode,开发语言,算法,数据结构,蓝桥杯)