题目描述

在这里插入图片描述
提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109

解题思路一

暴力解
头到尾遍历整个数组。
用一个变量 first 记录第一次遇到 target 的索引。
继续遍历,用另一个变量 last 不断更新最后一次遇到 target 的索引。
如果遍历结束后 first 仍然是初始值(例如 -1),说明目标值不存在,返回 [-1, -1]。
否则,返回 [first, last]。
代码实现:

/*** Note: The returned array must be malloced, assume caller calls free().*/
int* searchRange(int* nums, int numsSize, int target, int* returnSize) {int* result = (int*)malloc(sizeof(int) * 2);*returnSize = 2;int i = 0;int first = -1, last = -1;for (i = 0; i < numsSize; i++) {if (nums[i] == target) {first = i;break;}}if (first == -1) {result[0] = -1;result[1] = -1;return result;}for (i = first; i < numsSize; i++) {if (nums[i] == target) {last = i;}}result[0] = first;result[1] = last;return result;
}

执行结果:
在这里插入图片描述

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {int first = -1,last=-1;for(int i=0;i<nums.size();++i){if(nums[i]==target){first = i;break;}}if(first==-1){return{-1,-1};}for(int i=nums.size()-1;i>=first;--i){if(nums[i]==target){last = i;break;}}return {first,last};}
};

在这里插入图片描述

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

解法二:二分查找

两次二分查找是最优解

一次查找用于定位第一个等于 target 的位置(左边界)。
另一次查找用于定位最后一个等于 target 的位置(右边界)。

.1 查找左边界(First Position)
我们需要修改二分查找的逻辑,使得当 nums[mid] == target 时,我们不立即返回,而是尝试在左半部分继续寻找,看看有没有更靠前的 target。
具体步骤:
初始化 left = 0, right = n-1, first_pos = -1。
初始化 left = 0,right = n-1,first_pos = -1。

进入 while (left <= right) 循环。
输入 while(left <= right) 循环。

计算 mid = left + (right - left) / 2。
计算 mid = left +(right - left)/ 2。

关键逻辑:
如果 nums[mid] > target,说明目标值在左侧,right = mid - 1。
如果 nums[mid] < target,说明目标值在右侧,left = mid + 1。
如果 nums[mid] == target,我们找到了一个 target。但它不一定是第一个。所以我们先将这个位置记录下来 first_pos = mid,然后继续在左半部分搜索,即 right = mid - 1,试图找到一个更小的索引。
循环结束后,first_pos 中存储的就是第一个目标值的位置。

2.2 查找右边界(Last Position)
逻辑与查找左边界非常相似,只是当找到 target 时,我们尝试在右半部分继续寻找。
具体步骤:
初始化 left = 0, right = n-1, last_pos = -1。
初始化 left = 0,right = n-1,last_pos = -1。

进入 while (left <= right) 循环。
输入 while(left <= right) 循环。

计算 mid = left + (right - left) / 2。
计算 mid = left +(right - left)/ 2。

关键逻辑:
如果 nums[mid] > target,说明目标值在左侧,right = mid - 1。
如果 nums[mid] < target,说明目标值在右侧,left = mid + 1。
如果 nums[mid] == target,我们找到了一个 target。但它不一定是最后一个。所以我们先将这个位置记录下来 last_pos = mid,然后继续在右半部分搜索,即 left = mid + 1,试图找到一个更大的索引。
循环结束后,last_pos 中存储的就是最后一个目标值的位置。
最终:先执行查找左边界的二分,如果没找到(返回-1),直接返回 [-1, -1]。如果找到了,再执行查找右边界的二分,最后将两个结果组合成 [first_pos, last_pos] 返回。

代码实现:

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {int first_pos= -1, last_pos = -1;int left=0,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{first_pos=mid;right = mid-1;}}if(first_pos==-1)return {-1,-1};left = 0; 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{last_pos=mid;left = mid+1;}}return {first_pos,last_pos};}
};

执行结果
在这里插入图片描述
复杂度分析:
时间复杂度:O(logn)
空间复杂度:O(1)
优化在第二次while循环时,只在 [first_pos, n-1] 范围内搜索而不是从【0,n-1】
在这里插入图片描述

思路三

巧用二分查找寻找边界(思路二的变体)

这个思路更加巧妙,它将问题转化为**“寻找第一个大于等于 target 的位置”** 和 “寻找第一个大于 target 的位置”。

寻找左边界:
我们执行一次二分查找,目的是找到第一个大于或等于 target 的元素的索引。这个索引就是我们要的左边界 left_bound。
这个查找过程也被称为 lower_bound。
寻找右边界:
我们再执行一次二分查找,目的是找到第一个大于 target 的元素的索引。
那么,这个索引减一,就是我们要的右边界 right_bound。
这个查找过程也被称为 upper_bound。
验证结果:
在找到 left_bound 后,需要检查一下 nums[left_bound] 是否真的等于 target。如果不是,或者 left_bound 越界了,说明 target 根本不存在,直接返回 [-1, -1]

#include <iostream>
#include <vector>class Solution {
public:std::vector<int> searchRange(std::vector<int>& nums, int target) {int first = -1;int last = -1;// 寻找第一个位置for (int i = 0; i < nums.size(); ++i) {if (nums[i] == target) {first = i;break; // 找到第一个就停止}}// 如果找不到,直接返回if (first == -1) {return {-1, -1};}// 寻找最后一个位置// 从后往前找会更高效for (int i = nums.size() - 1; i >= first; --i) {if (nums[i] == target) {last = i;break; // 找到第一个(从后往前看)就停止}}return {first, last};}
};

在这里插入图片描述

复杂度分析:
时间复杂度:O(logn)
空间复杂度:O(1)
ok,see you next time~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/93829.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93829.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/93829.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚幻基础:曲线

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录曲线&#xff1a;数值变化的曲线动画曲线动画曲线get curve value只有curve所在动画被播放才返回曲线数值没播放时 返回0一个曲线可以在多个动画中使用 且可以设置曲线的不同值曲线&#xff1a;数值变化的曲线 动画…

MFC随笔—不使用对话框资源模板创建对话框

在MFC程序中使用对话框时一般都是首先在资源模版里创建对话框资源,然后DoModal()或者Create显示出模式对话框或者非模式对话框。然而采用该方式创建出的对话框移植性差,从一个工程移动到另一个工程比较麻烦。 在MFC中还有另一种创建对话框的方法,即利用DLGTEMPLATE、DLGITEM…

第八十六章:实战篇:文本生成脚本 → TTS + 镜头 → 视频整合——让你的文字“动听”又“好看”!

AI导演链路前言&#xff1a;AI的“智能制片人”——文本 → 视频&#xff0c;你的想法“一键出片”&#xff01;第一章&#xff1a;痛点直击——传统视频制作&#xff0c;累到“吐血”&#xff01;第二章&#xff1a;探秘“智能制片厂”&#xff1a;流水线上的四大核心模块&…

Linux内核源码详解--缺页异常(Page Fault)处理的核心函数handle_pte_fault

handle_pte_fault 是 Linux 内核中处理缺页异常&#xff08;Page Fault&#xff09;的核心函数&#xff0c;负责根据页表项&#xff08;PTE&#xff09;的状态和访问权限&#xff0c;分发到不同的子处理逻辑&#xff08;如匿名页映射、文件页映射、写时复制、NUMA 迁移等&#…

基于混合注意力网络和深度信念网络的鲁棒视频水印技术基础理论深度解析

1. 引言随着数字媒体技术的迅猛发展和互联网的普及&#xff0c;视频内容的创作、传播和分享变得前所未有的便捷。然而&#xff0c;这种便利性也带来了严重的版权保护挑战。数字视频的易复制性使得盗版和非法传播成为困扰内容创作者和版权所有者的重大问题。传统的加密技术虽然能…

linux 之virtio 的驱动框架

1、基本知识 上一篇文章介绍了 virtio 的核心数据的实现和逻辑&#xff1a;linux 之 virtio 子系统核心的数据结构-CSDN博客 virtio 是对半虚拟化 hypervisor 中的一组通用模拟设备的抽象。它允许 hypervisor 导出一组通用的模拟设备&#xff0c;并通过一个通用的应用编程接口…

项目1总结其三(图片上传功能)

1、UploadService public interface UploadService {//上传图片String uploadImage(MultipartFile file, String type); }upload.location D:/upload Value("${upload.location}")private String uploadLocation;//文件上传路径Overridepublic String uploadImage(M…

Linux应用层开发--线程池介绍

Glib 线程池 1. 线程池简介 线程池是一种管理和重用多个线程的设计模式&#xff1a; 避免频繁创建/销毁线程的开销。提高性能与资源利用率。任务提交后&#xff0c;由线程池内的线程自动执行&#xff0c;任务执行完线程不会退出&#xff0c;而是继续等待下一个任务。 2. Gli…

【Python】Python 多进程与多线程:从原理到实践

Python 多进程与多线程&#xff1a;从原理到实践 文章目录Python 多进程与多线程&#xff1a;从原理到实践前言一、并发编程基础&#xff1a;进程与线程1.1 进程&#xff08;Process&#xff09;1.2 线程&#xff08;Thread&#xff09;1.3 进程与线程的关系二、Python 中的 &q…

electron-vite_18Less和Sass共用样式指定

项目中可以封装less公用样式和方法&#xff0c;比如自动以滚动条样式、单行省略号、多行省略号、display:none等&#xff1b;关于additionalData的配置生效,请在main.js中引入一个别的样式或vue组件中使用“<style lang“scss”><style>”找到electron.vite.config…

Python面试题及详细答案150道(71-80) -- 文件操作篇

《前后端面试题》专栏集合了前后端各个知识模块的面试题&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

python新工具-uv包管理工具

uv 是一个由 Astral (Ruff 的创建者) 开发的极速 Python 包和项目管理器&#xff0c;用 Rust 编写。它旨在作为传统 Python 包管理工具&#xff08;如 pip、pip-tools、pipx、poetry、pyenv、twine 和 virtualenv 等&#xff09;的替代品&#xff0c;通过其高性能和多功能集成&…

有关spring-ai的defaultSystem与systemMessage优先级

今天在写项目的时候想用nacos随时修改system的prompt&#xff0c;突然发现defaultSystem的优先级比systemMessage高很多&#xff0c;废话我就不说了&#xff0c;看图吧。你觉得证据不够&#xff1f;那这样呢&#xff1f;

#运维 | 前端 # Linux http.server 实践:隐藏长文件名,简短路径 (http://IP:port/别名 ) 访问

如何运行页面为 http://ip:port/名称 1. 准备文件目录 假设文件原始位置&#xff1a; /home/ubuntu/projects/yinran/ckd.html将它移动到子目录并改名为 index.html&#xff1a; mkdir -p /home/ubuntu/projects/yinran/ckd mv /home/ubuntu/projects/yinran/ckd.html \/home/u…

任务管理器不刷新

记录一个小问题&#xff1a; 进入任务管理器之后发现页面不会刷新&#xff0c;性能界面也是一致。解决办法&#xff1a;查看–>更新速度–>正常

2025-08-21 Python进阶9——__main__与lambda

文章目录1 \_\_main\_\_1.1 name 变量1.1.1 当模块作为主程序直接运行时1.1.2 当模块被其他模块导入时1.2 \_\_main\_\_ 的含义1.3 if \_\_name\_\_ \_\_main\_\_1.5 小结2 lambda表达式2.1 基本概念2.2 lambda 函数语法2.3 使用示例2.4 与高阶函数结合使用2.4.1 与 map () 结…

Java:将视频上传到腾讯云并通过腾讯云点播播放

功能需求:传入一个videoFile也就是视频字节流,返回腾讯云点播的视频保存url需要在腾讯云中寻找的配置信息:导入的依赖:<!--腾讯云点播--><dependency><groupId>com.tencentcloudapi</groupId><artifactId>tencentcloud-sdk-java</artifactId&…

Unity3D物理游戏网络同步指南

前言 Unity3D 物理游戏的网络同步是一个复杂但非常核心的话题。要实现一个流畅、公平且可扩展的多人物理游戏&#xff0c;需要深入的理解和精心的设计。 下面我将为你全面解析 Unity3D 物理游戏的网络同步&#xff0c;包括核心概念、主流方案、实现细节以及最佳实践。 对惹&…

Amazon Redshift 访问配置完整指南

概述 Amazon Redshift 是 AWS 提供的云端数据仓库服务,支持多种访问方式。本文将详细介绍如何配置 IAM 权限、使用 AWS 控制台 Query Editor v2,以及通过 SQL Workbench/J 等第三方工具连接 Redshift 集群。 目录 环境准备 IAM 权限配置 Redshift 用户管理 AWS 控制台访问 …

electron-vite_19配置环境变量

前端配罟环境变量主要通过项目根目录下的.env系列文件实现&#xff0c;不同框架(如Vue、React)或构建工具(如Vite、Webpack)的具体操作略有差异&#xff0c;但核心逻辑均为通过环境变量文件区分开发、测试、生产等环境。方案1: 直接在根目录新建.env文件 1.在根目录新建 .env.d…