当前位置: 首页 > article >正文

LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)

LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
        • 思路一(一次二分查找+挨个搜索):
        • 思路二(两次二分查找):
      • 代码实现
        • 代码实现(思路一(二分查找+挨个搜索)):
        • 代码实现(思路二(两次二分查找)):
        • 以思路二为例进行调试

题目描述:

给你一个按照非递减顺序排列的整数数组 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

题解:

解题思路:

思路一(一次二分查找+挨个搜索):

1、通过二分查找找到第一个等于target的元素,若没查找到等于target的元素则返回[-1,-1]。若查找到target的元素,则从此位置开始分别向左向右挨个判断元素值是否为target,直至元素值不等于target为止,此时更新最左侧和最右侧的下标。

2、复杂度分析:
① 时间复杂度:O(n),n代表数组中元素的个数,最坏的情况:数组中的元素都为target。
② 空间复杂度:O(1)。

思路二(两次二分查找):

1、可以通过二分查找先查找到等于target值元素的最左侧下标,再采用二分查找找到等于target值元素的最右侧的下标。
① 当元素值等于target值的时候,再在左侧区间查找是否有等于target值的元素,有则更新等于target的左侧下标,直至左侧子区间不存在等于target值的元素。
② 当元素值等于target值的时候,再在右侧区间查找是否有等于target值的元素,有则更新等于target的右侧下标,直至右侧子区间不存在等于target值的元素。

2、复杂度分析
① 时间复杂度:O(logn),n代表数组中元素的个数。
② 空间复杂度:O(1)。

代码实现

代码实现(思路一(二分查找+挨个搜索)):
class Solution1 {
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
            // 初始化返回的结果为 {-1, -1},表示未找到目标值
            vector<int> ans = {-1, -1};

            // 如果数组为空,直接返回 {-1, -1}
            if (nums.empty())
            {
                return ans;
            }
            
            // 初始化二分查找的左右边界
            int left = 0, right = nums.size() - 1;
            int mid;
            
            // 使用二分查找寻找目标值的某个位置
            while (left <= right)
            {
                // 计算中间位置
                mid = left + (right - left) / 2;
           
                // 如果中间值大于目标值,缩小右边界
                if (nums[mid] > target)
                {
                    right = mid - 1;
                }
                // 如果中间值小于目标值,缩小左边界
                else if (nums[mid] < target) {
                    left = mid + 1;
                }
                // 如果找到了目标值,记录当前中间值位置,并跳出循环
                else {
                    ans[0] = mid; // 目标值的起始位置
                    ans[1] = mid; // 目标值的结束位置
                    break; // 找到目标值,跳出循环
                }
            }
            
            // 如果找到了目标值(即ans[0]不为-1)
            if (ans[0] != -1)
            {
                // 在找到的位置周围扩展,查找目标值的左边界和右边界
                left = ans[0];
                right = ans[1];
                
                // 从左边界开始,向左扩展,直到不等于目标值为止
                while (left >= 0 && nums[left] == target){
                    left--;
                }
                // 更新目标值的左边界
                ans[0] = left + 1;

                // 从右边界开始,向右扩展,直到不等于目标值为止
                while (right < nums.size() && nums[right] == target){
                    right++;
                }
                // 更新目标值的右边界
                ans[1] = right - 1;
            }
            
            // 返回目标值的范围
            return ans;
        }
};
代码实现(思路二(两次二分查找)):
class Solution2 {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> ans = {-1, -1};
        
        if (nums.empty()) {
            return ans;
        }
        
        // 寻找左边界
        int left = 0, 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 - 1;
            } else {
                // 找到目标,继续向左移动 right 确保是最左边的位置
                right = mid - 1;
            }
        }
        //这里不能使用left<=right来判断是否找到target,因我们再继续查找其他的target时会令最终的left>right
        // 如果 left 超出了数组范围,或者 nums[left] 不是 target,说明 target 不存在
        if (left >= nums.size() || nums[left] != target) {
            return ans;
        }
        ans[0] = left;
        
        // 寻找右边界
        right = nums.size() - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                // 找到目标,继续向右移动 left 确保是最右边的位置
                left = mid + 1;
            }
        }
        ans[1] = right;
        
        return ans;
    }
};
以思路二为例进行调试
#include<iostream>
#include <vector>
using namespace std;

class Solution2 {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> ans = {-1, -1};
        
        if (nums.empty()) {
            return ans;
        }
        
        // 寻找左边界
        int left = 0, 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 - 1;
            } else {
                // 找到目标,继续向左移动 right 确保是最左边的位置
                right = mid - 1;
            }
        }
        //这里不能使用left<=right来判断是否找到target,因我们再继续查找其他的target时会令最终的left>right
        // 如果 left 超出了数组范围,或者 nums[left] 不是 target,说明 target 不存在
        if (left >= nums.size() || nums[left] != target) {
            return ans;
        }
        ans[0] = left;
        
        // 寻找右边界
        right = nums.size() - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                // 找到目标,继续向右移动 left 确保是最右边的位置
                left = mid + 1;
            }
        }
        ans[1] = right;
        
        return ans;
    }
};

int main(int argc, char const *argv[])
{
    vector<int> nums={5,7,7,8,8,10};
    int target= 8;
    Solution2 s2;
    vector<int>ans= s2.searchRange(nums,target);
    cout<<ans[0]<<"  "<<ans[1];
    return 0;
}

LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34)原题链接
欢迎大家和我沟通交流(✿◠‿◠)


http://www.kler.cn/a/558084.html

相关文章:

  • 技术解析 | 适用于TeamCity的Unreal Engine支持插件,提升游戏构建效率
  • netty基础知识梳理和总结
  • 数据库面试知识点总结
  • [Android]浏览器下载的apk文件无法识别无法安装问题
  • 《AI与NLP:开启元宇宙社交互动新纪元》
  • Django 连接(sqlserver)数据库方法
  • SHELL32!Shell_MergeMenus函数分析
  • 蓝桥杯拔河问题(前缀和与差分,multiset,区间冲突)
  • 基于Transformer的语音障碍分析方法
  • MAC快速本地部署Deepseek (win也可以)
  • 工业机器视觉的“眼睛”:如何利用镜头获取精准图像
  • [含文档+PPT+源码等]精品大数据项目-Django基于机器学习实现的市区游客满意度可视化分析系统
  • 【论文阅读】SAM-CP:将SAM与组合提示结合起来的多功能分割
  • Uniapp 设计思路全分享
  • DeepSeek R1/V3满血版——在线体验与API调用
  • Error [ERR_REQUIRE_ESM]: require() of ES Module
  • MySQL的Union和OR查询
  • Vite 和 Webpack 的区别和选择
  • 靶场之路-Kioptix Level-1 mod_ssl 缓冲区溢出漏洞
  • CDefFolderMenu_MergeMenu函数分析之添加了分割线和属性菜单项两项