033.搜索旋转排序数组

news2024/11/16 11:57:33

题意

整数数组 nums 按升序排列,数组中的值 互不相同

在传递给方法之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你旋转后的数组 nums 和一个整数 target,如果 nums 中存在这个目标值 target,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

难度

中等

示例

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

分析 1

这道题咋眼一看,有点绕,给一个旋转后的数组,和一个目标值,并要求我们找到这个目标值的下标。

但稍微分析一下就知道,就是在一个数组当中查找一个目标值,如果不考虑时间复杂度的话,我们可以直接遍历一遍,找到就返回下标,找不到就返回-1。

超级简单:

class Solution {
    public int search(int[] nums, int target) {
        for(int i = 0;i < nums.length;i++){
            if(nums[i] == target)
                return i;
        }
        return -1;
    }
}

来看一下效率:

效率不错,但要时间复杂度为对数级别。那就要考虑别的算法

分析 2

我们知道,在一个有序的数组里面去判断一个数是否存在,可以利用二分查找,时间复杂度刚好就是$O(\log{n})$。

但这道题只是部分有序(因为旋转了),该怎么去判断呢?

闭上眼,想一下。

从任意位置将这个部分有序的数组分开,那么分开之后的两部分必然有一部分是有序的!

比如:

nums = [4,5,6,7,0,1,2]      
nums = [4] [5,6,7,0,1,2]	breakPos = 1
nums = [4,5] [6,7,0,1,2]    breakPos = 2
nums = [4,5,6] [7,0,1,2]    breakPos = 3
nums = [4,5,6,7] [0,1,2]    breakPos = 4
nums = [4,5,6,7,0] [1,2]    breakPos = 5
nums = [4,5,6,7,0,1] [2]    breakPos = 6

果然,至少有一部分是有序的。那我们是不是就可以从有序的部分当中去寻找 target 呢?

可以是可以,但时间复杂度并不是 $O(\log{n})$,还要加上 breakPos 分割后无序的部分,合起来就是$O(n + \log{n})$,显然也不符合题目的要求。

考虑下面的思路:

  • 如果[lef,breakPos - 1]是有序的,而且nums[lef] <= target && target < nums[breakPos],那么答案肯定在[lef, breakPos - 1],直接调整上界rig到breakPos - 1。
  • 如果[breakPos,rig]是有序的,而且nums[breakPos] < target && target <= nums[rig],那么答案肯定在[breakPos,rig]中,调整下界lef到breakPos即可。

也就是说,我们通过判断有序的部分,来决定下一步的查找范围。

  • 只有在有序区间内才可以通过区间两端的数值判断 target 是否在其中。
  • 判断有序区间还是乱序区间:left <= right 是顺序区间,否则乱序区间。
  • 每次二分至少存在一个有序区间。
class Solution {
    public int search(int[] nums, int target) {
        int siz = nums.length; // 数组长度
        int lef = 0, rig = siz - 1; // 初始化左右指针
        while (lef <= rig) { // 当左指针小于等于右指针时进行循环
            int mid = (lef + rig) >> 1; // 计算中间索引,使用右移运算符相当于除以 2
            if (nums[mid] == target) // 如果中间元素等于目标值,返回中间索引
                return mid;
            if (nums[0] <= nums[mid]) { // 如果左半部分有序
                if (nums[0] <= target && target < nums[mid]) // 如果目标值在左半部分范围内
                    rig = mid - 1; // 移动右指针
                else
                    lef = mid + 1; // 否则移动左指针
            } else { // 右半部分有序
                if (nums[mid] < target && target <= nums[siz - 1]) //如果目标值在右半部分范围内
                    lef = mid + 1; // 移动左指针
                else
                    rig = mid - 1; // 否则移动右指针
            }
        }
        return -1; // 如果未找到目标值,返回 -1
    }
}

我们来分析一下代码的关键部分:

第一步,初始化

  • siz:数组长度。
  • lef 和 rig:左右指针,分别初始化为数组的第一个和最后一个索引。

第二步,二分查找

计算中间索引 mid;如果 nums[mid] 等于目标值 target,直接返回 mid。

检查数组的左半部分是否有序(nums[0] <= nums[mid])。

如果左半部分有序,并且目标值在左半部分范围内(nums[0] <= target && target < nums[mid]),移动右指针到 mid - 1;否则,移动左指针到 mid + 1。

如果右半部分有序,并且目标值在右半部分范围内(nums[mid] < target && target <= nums[siz - 1]),移动左指针到 mid + 1;否则,移动右指针到 mid - 1。

第三步,如果循环结束仍未找到目标值,返回 -1。

假设数组为 [4, 5, 6, 7, 0, 1, 2],目标值 target 为 0,我们来模拟一下整个题解过程:

  • 1.初始 lef = 0,rig = 6,mid = 3,nums[mid] = 7。
  • 2.nums[0] <= nums[mid],左半部分有序。
  • 3. 0 不在左半部分范围内,移动左指针 lef = 4。
  • 4.更新 mid = 5,nums[mid] = 1。
  • 5.nums[4] <= nums[mid],右半部分有序。
  • 6. 0 在右半部分范围内,移动右指针 rig = 5。
  • 7.更新 mid = 4,nums[mid] = 0,找到目标值,返回 4。

总结

遇到 O(log n) 的题目,首先想到的就是二分查找,这道题也是一样,只不过在二分查找的基础上,增加了一些判断条件。而二分查找的关键是找到有序的部分。

力扣链接:. - 力扣(LeetCode)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python系列】Python 中的运算符:基础与高级用法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

1898java疫情防控管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 疫情防控管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发…

使用LabVIEW进行大数据数组操作的优化方法

针对大数据量数组操作&#xff0c;传统的内存处理方法可能导致内存不足。通过LabVIEW的图像批处理技术&#xff0c;可以有效地进行大数据数组操作&#xff0c;包括分块处理、并行处理和内存优化等。这种方法能显著提高处理效率和系统稳定性。 图像批处理的优势 内存优化&#…

navi_cat查看数据库的连接密码

Navi_Cat 建立连接&#xff0c;来访问数据库。可惜&#xff0c;忘记了数据库密码&#xff0c;没事&#xff0c;这么搞。 首先先导出链接&#xff0c;再从链接里取出被加密的密码&#xff0c;然后找个可在线运行PHP的网站&#xff08;代码在线运行 - 在线工具&#xff09;&…

ROS云课三分钟外传之CoppeliaSim_Edu_V4_1_0_Ubuntu16_04

三分钟热度试一试吧&#xff0c;走过路过不要错过。 参考之前&#xff1a; 从云课五分钟到一分钟之v-rep_pro_edu_v3_6_2-CSDN博客 git clone https://gitcode.net/ZhangRelay/v-rep_pro_edu_v3_6_2_ubuntu16_04.gittar -xf v-rep_pro_edu_v3_6_2_ubuntu16_04/V-REP_PRO_EDU…

Python爬取城市空气质量数据

Python爬取城市空气质量数据 一、思路分析1、寻找数据接口2、发送请求3、解析数据4、保存数据二、完整代码一、思路分析 目标数据所在的网站是天气后报网站,网址为:www.tianqihoubao.com,需要采集武汉市近十年每天的空气质量数据。先看一下爬取后的数据情况: 1、寻找数据…

网络空间安全数学基础·多项式环与有限域

5.1 多项式环&#xff08;掌握&#xff09; 5.2 多项式剩余类环&#xff08;理解&#xff09; 5.3 有限域&#xff08;熟练&#xff09; 5.1 多项式环 定义&#xff1a;设F是一个域&#xff0c;称是F上的一元多项式&#xff0e; 首项&#xff1a;如果an≠0&#xff0c;则称 a…

618数码产品有什么推荐?四大2024“宝藏”数码产品推荐!

随着618购物节的热情逐渐升温&#xff0c;你是否在繁多且诱人的商品海洋中迷失方向&#xff0c;难以找到那最心仪的宝贝&#xff1f;团团在此特别为你精心挑选了一系列经过亲身体验的优质好物。这些推荐不仅时尚前沿&#xff0c;更贴合你的日常生活需求&#xff0c;确保实用与品…

A6500-LC LVDT 前置器,用于A6500-UM, 导轨安装

电源 22.5V to 32VDC <30mA <0.1%/V <60V( 使用SELV/PELV 供电电源) 约2.2Vrms,5kHz IP20 IEC 60529 -35C to 75C(-31F to 167F) -35C to 85C(-31F to 185F) 电流损耗 供电电压对 运行温度 存储温度 0.35mm(0.014 in ),10 to 55Hz 15g 根据 EN 60068-2-27 根据IEC 613…

Ubuntu server 24 (Linux) sudo 免输密码

1 sudo 使用要输入密码&#xff0c;费时费力。 2 sudo命令免输密码&#xff0c;需要修改/etc/sudoers文件 #本文以test用户为例,#允许不需要输入密码执行 sudo vi /etc/sudoers test ALL(ALL) NOPASSWD: ALL %sudo ALL(ALL:ALL) ALL --> #%sudo ALL(ALL:ALL) ALL#所有…

数据中心网络架构设计与优化

数据中心是现代企业和组织的核心基础设施&#xff0c;它们用于存储、处理和传输大量的数据和信息。为了满足不断增长的数据需求和提供可靠的服务&#xff0c;设计和优化数据中心网络架构至关重要。 首先&#xff0c;数据中心网络架构设计需要考虑可扩展性。随着业务的增长&…

技术对比:eMMC、SD NAND与NOR Flash存储特性详解

在电子技术迅猛前进的今天&#xff0c;存储技术成为了整个行业发展的基石。SD NAND、eMMC和NOR Flash&#xff0c;这三种存储技术各自以其独特的架构和特性&#xff0c;满足了多样化的存储需求。让我们来看看它们之间的一些关键对比&#xff1a; 1. 存储单元架构&#xff1a; S…

gitlab之cicd的gitlab-runner cicd实践-rpm离线安装

目录 概述资源官方资源离线资源 操作环境验证gitlab-runner安装注意事项重启向gitlab注册CICD流程测试 概述 gitlab此文使用rpm离线安装的方式&#xff0c;使用 gitlab-runner dockerfile构建运行环境&#xff1a; 如有兴趣可以参考这篇文章   gitlab选择 docker-compose 执行…

前端面试题】—53道常见NodeJS基础面试题(附答案)

Node. js是一个不错的选择&#xff0c;它是基于JavaScript语法的一套服务器端&#xff08;后端&#xff09;语言。想要在企业中做得更好&#xff0c;开发者需要更多地了解它&#xff0c;并掌握它的有关用法。 1、你了解 Node. js吗&#xff1f; Node. js是一个基于 Chrome v8引…

移动安全赋能化工能源行业智慧转型

随着我国能源化工企业的不断发展&#xff0c;化工厂中经常存在火灾爆炸的危险&#xff0c;特别是生产场所&#xff0c;约有80%以上生产场所区域存在爆炸性物质。而目前我国化工危险场所移动通信设备的普及率高&#xff0c;但是对移动通信设备的安全防护却有所忽视&#xff0c;包…

R语言探索与分析19-CPI的分析和研究

一、选题背景 CPI&#xff08;居民消费价格指数&#xff09;作为一个重要的宏观经济指标&#xff0c;扮演着评估通货膨胀和居民生活水平的关键角色。在湖北省这个经济活跃的地区&#xff0c;CPI的波动对于居民生活、企业经营以及政府宏观经济政策制定都具有重要的影响。因此&a…

信息学奥赛初赛天天练-22-C++基础关键字、进制转换、结构体与联合体的实用技巧大揭秘

PDF文档公众号回复关键字:20240607 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1 在C中&#xff0c;下面哪个关键字用于声明一个变量&#xff0c;其值不能被修改&#xff1f;&#xff08; &#…

C#上位机开发

目录 一、上位机简介二、C#语法三、新建VS工程四、WinForm控件4.1 属性4.2 事件4.3 窗体方法4.4 常用控件4.5 布局 五、Serial上位机5.1 UI界面设计5.2 功能设计 六、项目打包成安装包6.1 前提准备6.2 打包步骤 一、上位机简介 在单片机项目开发中&#xff0c;上位机也是一个很…

因为宇宙一片漆黑,所以地球才有昼夜之分,宇宙为什么是黑的?

因为宇宙一片漆黑&#xff0c;所以地球才有昼夜之分&#xff0c;宇宙为什么是黑的&#xff1f; 地球为何会有昼夜之分&#xff1f; 乍一看&#xff0c;这个问题很是简单&#xff0c;当然是因为地球一直在自转了&#xff0c;当地球的一部分被太阳照射时就是白昼&#xff0c;而…

【中间件系列】浅析redis是否适合做消息队列

文章目录 一、简单的list消息队列1.命令示例2.伪代码示例3.方案优劣 二、Pub/Sub发布订阅1.消息丢失2.消息堆积 三、相对成熟的Stream1.redis命令介绍2.多消费者组测试3.Stream会持久化吗&#xff1f;4.消息堆积如何解决&#xff1f; 总结 用redis也是比较久了&#xff0c;并且…