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

news/2025/2/23 5:25:08

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.niftyadmin.cn/n/5862984.html

相关文章

基于腾讯云大模型知识引擎×DeepSeek构建八字、六爻赛博算卦娱乐应用

引言 随着DeepSeek的火爆&#xff0c;其强大的思维链让不少人越用越香&#xff0c;由于其缜密的思维和推理能力&#xff0c;不少人开发出了不少花里胡哨的玩法&#xff0c;其中一种就是以八字、六爻为代表的玄学文化正以“赛博玄学”的新形态席卷年轻群体。 针对于八字、六爻…

RAG检索中使用一个 长上下文重排序器(Long Context Reorder) 对检索到的文档进行进一步的处理和排序,优化输出顺序

使用一个长上下文重排序器对检索到的文档进行进一步的处理和排序&#xff0c;优化输出顺序。 优化前的检索内容&#xff0c;顺序混乱&#xff1a; 优化后的检索内容&#xff0c;按顺序排列&#xff1a; 使用 LongContextReorder 对检索得到的文档进行重新排序。这一步的目的…

ThinkORM模型静态方法create好像对MongoDB不支持

软件版本 think-orm&#xff1a;3.0PHP&#xff1a;8.4.1MongoDB&#xff1a;8.0.4 &#xff08;本地单数据 非集群&#xff09;注&#xff1a;我是在 webman 框架下使用think-orm&#xff0c;并非在 thinkphp框架下使用 使用场景 定义的模型如下&#xff1a; <?php na…

嵌入式硬件篇---数字电子技术中的时序逻辑

文章目录 前言简介1. 关键延迟时间的定义与作用(1) 传输延迟&#xff08;Propagation Delay&#xff09;定义作用示例 (2) 时钟到输出延迟&#xff08;Clock-to-Q Delay, Tcq&#xff09;定义作用示例 (3) 建立时间&#xff08;Setup Time, Tsetup&#xff09;定义作用示例 (4)…

k8s集群内的pod连接集群外部的mysql, k8s集群内部服务如何连接集群外部mysql? 一文搞明白

一、为什么不将mysql服务部署到k8s集群中使用呢&#xff1f; 1.有状态服务在K8s中的管理比较复杂&#xff0c;特别是持久化存储的问题。虽然K8s有StatefulSet和PV/PVC&#xff0c;但配置和维护起来需要更多工作,同时以下问题仍需解决&#xff1a;-存储可靠性&#xff1a;如果使…

Docker国内镜像源部署deepseek

‌部署deepseek时Docker拉取国内镜像失败可能是由于国内网络环境复杂或镜像源配置不正确导致的‌。 具体原因可能包括&#xff1a; ‌网络问题‌&#xff1a;国内网络环境复杂&#xff0c;可能导致访问国内镜像仓库的速度较慢或无法访问&#xff0c;进而影响Docker镜像的拉取…

RTSP场景下的RTP与RTCP

一、RTP 数据包格式&#xff08;RFC 3550 Section 5.1&#xff09; 1. RTP 头部结构 0 1 2 30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -------------------------------- |V2|P|X| CC |M|…

微信小程序数据绑定与事件处理:打造动态交互体验

在上一篇中&#xff0c;我们学习了如何搭建微信小程序的开发环境并创建了一个简单的“Hello World”页面。然而&#xff0c;一个真正的小程序不仅仅是静态内容的展示&#xff0c;它需要与用户进行动态交互。本文将深入探讨微信小程序中的数据绑定和事件处理机制&#xff0c;通过…