LeetCode高频题33. 搜索旋转排序数组

提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题


文章目录

  • LeetCode高频题33. 搜索旋转排序数组
    • @[TOC](文章目录)
  • 题目
  • 一、审题
  • 二、解题
  • 但是我们就要学,万一nums有重复值怎么办????
  • 这种L,M,R不全相等的二分具体该如何找到target呢?此时M!=target,是前提条件哦!
  • 代码不需要记忆,只需要记住:[L],[M],[R]不全相等,可直接利用二分查找,如果全相等,挪动L,让他们仨,不全相等!
  • 如果所有值都不会重复,独一无二出现,那还有一种写法,本身就满足了L,M,R不全相等,就是我上面代码的其中一个小分支,你只需要确定target在哪边就行
  • 总结

题目

整数数组 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) 的算法解决此问题。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/search-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


一、审题

示例 1:

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

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

输入:nums = [1], target = 0
输出:-1

提示:

1 <= nums.length <= 5000
-104 <= nums[i] <= 104
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-104 <= target <= 104


二、解题

可能旋转了,而且k是不告诉你的

也可能没有转过
但是你仍然要用二分法log(n)找到一个target

这里考的就是条件分类

注意:nums 中的每个值都 独一无二

而啥时候L–M–R上寻找target可以用二分法???
就是当L,M,R处数字有一个与别的数不相等就行,当L=M=R时,没有办法用二分法的


本题又说了注意:nums 中的每个值都 独一无二
就是任意位置[L],[M],[R]绝不可能相等
所以就可以二分

但是我们就要学,万一nums有重复值怎么办????

不妨设f就是二分查找arr的L–R上的target,能找到返回下标,不能就返回-1!

先看M,如果M就是target,直接返回M就行,说明找到了……

但是上面不行,则下面,一定是target!=[M]

如果你看[L],[M],[R]三者是不是不全相等,不全相当就可以继续二分查找!

但是先不看[L],[M],[R]三者是不是不全相等这种情况,咱们先讨论[L],[M],[R]三者全相等的情况:
[L]=[M]=[R]!=target

比如:2 2 2 2 2 1 2
实际上就是1 2 2 2 2 2 2旋转来的
求target=1,怎么求???
最开始L=0,R=N-1=6,M=(L+R)/2=3
你会发现

这种情况压根没法二分!

咋搞呢
L++,直到L不是[M]那个数了,就可以在L–R上二分了,满足了不全相等的条件

但是,有可能你一直L++都发现[L]=[M],最后L=M时,咋搞???
说明L–M全是[M],而且都不是target【target!=M】,显然,你得去M+1–R上二分

可是你发现……可能L一直挪挪挪动到M时,走过的距离是O(N/2),这都o(n)复杂度了????
????
????
没办法,题目虽然叫你写o(log(N))的复杂度,但是没用办法绝对
这是最可恶的出题者!!!

一般来讲,可能测试案例就没有这种o(n)的事情

大多情况测试案例都是能迅速找到可以二分的L的…………
很尴尬吧,很尴尬!

好,上面我们说,只要当L遇到和[M]不相等时,就是不全相等【不论此时L=M,还是不等于M】,可以在L–R上二分了
区别就是L!=M时,可以直接看不全相等的分支,
但是L=M时,需要让L=M+1,再去从头看右半部分,回去调用f,为啥,因为你还没有找到[L],[M],[R]不全相等的情况呢,还得继续找去

综合就是代码:

上面的continue就是先让L=M+1,再看

这种L,M,R不全相等的二分具体该如何找到target呢?此时M!=target,是前提条件哦!

不全相等,就可以把条件分开,尽量找到target所在的一个有序区间
有几种情况

(1)可能是[L]!=[M]
(2)可能是[M]!=[R]

这都是不全相等的状况
(1)可能是[L]!=[M]
如果此时[L]>[M]
为什么会出现[L]>[M]???
还不是因为你M–R被旋转到后面了,当然,不论如何我们的arr如何旋转,旋转之后M–R是有序的

比如:下面这种,5>1显然就是M–R被旋转到后面了
现在其实很简单,此刻从M–R一定是升序,这个你认可的吧,就两部分!但M–R都是有序的
所以你只需要看target在哪边就行,然后接着去那边二分查找即可

相反,如果[L]<[M],说明L–M还没有被旋转到后面,L–M之间必定有序,本身题目就说了是升序的

所以你看看target是在L–M上呢还是M+1–R上,继续去二分查找

就像下面这样:

(2)不全相等的话可能是[M]!=[R]
这时候你发现,如果[M]<[R],显然M–R上有序,如果target在这范围内,去这里二分查找,不行就L–M-1上二分

如果[M]>[R],显然就是因为被旋转动过的,L–M-1一定是有序的,所以如果target在L–M-1上,直接去二分就行,不行就M–R上二分

总之,这么做的目的,就是为了尽可能让[L],[M],[R]尽可能不全相等,然后直接利用二分查找
在找的时候,通过条件尽快定位target

就像下面:

代码不需要记忆,只需要记住:[L],[M],[R]不全相等,可直接利用二分查找,如果全相等,挪动L,让他们仨,不全相等!

你搞懂这个核心思想:不全相等的L,M,R才能直接二分,就好办
所以有了这个条件,手撕代码它很好确定
随意写,不一定要跟我的代码相同,只要每次二分边界确定好就行

        //复习://只需要记住:[L],[M],[R]不全相等,可直接利用二分查找,如果全相等,挪动L,让他们仨,不全相等!public int searchReview(int[] nums, int target) {if (nums == null || nums.length == 0) return -1;int L = 0;int R = nums.length - 1;//想尽一切办法二分查找while (L <= R){int M = L + ((R - L) >> 1);if (nums[M] == target) return M;//位置找到了返回//nums[M] != target//如果[L],[M],[R]全相等,挪动L,让他们仨,不全相等!if (nums[M] == nums[L] && nums[M] == nums[R]){while (nums[L] == nums[M] && L < M) L++;//L最多撞到M,然后退出//如果L!=M,说明提前nums[L] != nums[M] 也!=target,那就满足不全相等,可以下面操作二分if (L == M){//如果L==M了,说明左边压根不可能有target,下次去M+1--R上继续二分L = M + 1;continue;//下面就别操作了}}//到了这,[L],[M],[R]不全相等,且nums[M] 也!=target//既然是不全相等,看看是[L] != [M],还是[R] != [M],不论怎样,咱们都要二分,只不过看target在哪?if (nums[L] != nums[M]){//此时再看[L] > [M]还是 [L] < [M]if (nums[L] > nums[M]){//说明L被旋转到前面了,而M+1--R是一定有序的,旋转到后面了if (nums[M + 1] <= target && target <= nums[R]) L = M + 1;//target在右边else R = M;//否则target就在左边}else {//nums[L] < nums[M],说明L--M有序的if (nums[L] <= target && target <= nums[M]) R = M;//target在左边else L = M + 1;//否则target就在右边}}else {//[R] != [M]//此时再看看[M] < [R] 还是 [M] > [R]if (nums[M] < nums[R]){//说明M--R有序if (nums[M] <= target && target <= nums[R]) L = M + 1;//target在右边else R = M - 1;//否则target就在左边}else {//nums[M] > nums[R],说明L--M上有序if (nums[L] <= target && target <= nums[M]) R = M + 1;//target在左边else L= M + 1;//否则target就在右边}}}//一直二分没有,L>R,return -1;}

测试:

    public static void test(){int[] arr = {4,5,6,7,8,1,2,3};int target = 8;Solution solution = new Solution();System.out.println(solution.search(arr, target));System.out.println(solution.searchReview(arr, target));}public static void main(String[] args) {test();}

问题不大:

4
4

LeetCode测试:


老牛逼了!

反正思想就这么简单,代码你随意敲就行

如果所有值都不会重复,独一无二出现,那还有一种写法,本身就满足了L,M,R不全相等,就是我上面代码的其中一个小分支,你只需要确定target在哪边就行

这个代码是上面代码的缩减版本,只满足某一个小分支

但是上面那个代码是最强大的,因为我们允许上面那个代码有重复值出现!!!

public int search(int[] nums, int target) {//实际上,这要是不旋转,直接就是一个二分查找的问题//不过旋转了就得想办法二分查找if (nums == null || nums.length == 0) return -1;int L = 0;int R = nums.length - 1;while (L <= R){int mid = L + ((R - L) >> 1);//重点,因为要不断更新左边右边if (nums[mid] == target) return mid;if (nums[mid] > nums[R]){//右边无序--确实被旋转了,就看target在哪了if (nums[L] <= target && target < nums[mid]) R = mid - 1;else L = mid + 1;}else {//右边有序//显然nums[mid] <= nums[R]if (nums[mid] < target && target <= nums[R]) L = mid + 1;else R = mid - 1;}}return -1;//如果L越界R都没有找到}

这方法核心思想其实也是,都不考虑要不全相等,


总结

提示:重要经验:

1)[L],[M],[R]不全相等,可直接利用二分查找,如果全相等,挪动L,让他们仨,不全相等!再去二分
2)本题相当于直接告诉你L,M,R已经不全相等了,就更好写。
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

LeetCode高频题33. 搜索旋转排序数组相关推荐

  1. Leetcode刷题33. 搜索旋转排序数组

    升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] ). 请你在数组中搜索 target ,如果数组 ...

  2. Leetcode刷题 33.搜索旋转排序数组

    分析: 首先看到这题的第一印象是题目很长,感觉很复杂,但仔细看下来之后发现题目中间一段对解题没有任何的帮助,重点在最后一句,大概意思就是在目标数组中找到目标数据,并传出对应位置,否则传出-1 清楚了目 ...

  3. leetcode刷题:搜索旋转排序数组

    题目: 分析:当我们将数组旋转的时候,就无法再保证数组是完全有序的了,但是我们可以判断出那块是有序的.然后在进行比较和查找 如下代码: class Solution { public:int sear ...

  4. 【LeetCode笔记】33. 搜索旋转排序数组(Java、二分法)

    文章目录 题目描述 思路 & 代码 更新版 题目描述 值互不相同:不用考虑重复值情况(要不然比较麻烦) 思路 & 代码 重点在于保证O(logn)的时间复杂度 看成两个数组:前半段 & ...

  5. LeetCode (二分小专题)33搜索旋转排序数组34在排序数组中查找元素的第一个和最后一个位置35搜索插入位置

    前言 国庆前最后一次打卡,国庆后继续开启,公众号bigsai回复进群欢迎加入打卡,如有帮助记得点赞收藏. 近期打卡记录: LeetCode 32最长有效括号(困难) (本周) LeetCode 30串 ...

  6. LeetCode 33. 搜索旋转排序数组 golang

    33. 搜索旋转排序数组 三个测试用例, 这个题的难度是二分法的左侧条件很难写出来. 4 5 6 0 1 2 3 1 2 3 4 5 6 0 5 1 2 3 4 ( 例如,数组 [0,1,2,4,5, ...

  7. LeetCode—33. 搜索旋转排序数组

    33. 搜索旋转排序数组 题目描述:整数数组 nums 按升序排列,数组中的值 互不相同 . 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length ...

  8. 数组的合并和升序排列_leetcode 33 搜索旋转排序数组

    给你一个升序排列的整数数组 nums ,和一个整数 target . 假设按照升序排序的数组在预先未知的某个点上进行了旋转.(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0 ...

  9. 【LintCode 题解】小米面试算法题:搜索旋转排序数组

    题目描述 假设有一个排序的按未知的旋转轴旋转的数组(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2).给定一个目标值进行搜索,如果在数组中找到目标值返回数组中的索引位置,否则返回 ...

最新文章

  1. ava.lang.UnsatisfiedLinkError:
  2. mysql8.0用mybatis哪个版本_SpringBoot整合MyBatis与MySql8.0
  3. pycharm黄色高亮提示:Default argument value is mutable
  4. 使用MAT工具分析内存溢出
  5. 最近在群里┏━━━━━━━━━飞鸽传书━━━━━━━━━━┓
  6. python123第6周答案_Python123测验6: 组合数据类型 (第6周)
  7. SQL DateTime数据类型注意事项和限制
  8. delphi listview动态添加图片_Java 添加PDF图章(印章)——图片图章、动态图章
  9. python函数的四个特点_Python面向对象三大特征之封
  10. ZKTeco 中控考勤机M300 plus java开发步骤 使用jacob 调用中控考勤机dll(详细配置)
  11. 电压、电流、频率计算常见公式以及参数认识
  12. 一、rsync +cwrsync实现windows和linux的文件同步
  13. 24个非洲青年,为啥跑来阿里“上学”?
  14. 语音服务器搭建,教你自建团队语音服务器
  15. uniapp图片加载不出来的解决方案
  16. 网站调用服务器字体,网站调用字体库
  17. 能净化空气的PC电源,配置也很不错,艾湃电竞AP-550Ti体验
  18. 新建vue-cli项目body与页面边框存在间隙
  19. 泊松重建(Poisson Surface Reconstruction)
  20. JAVA实现资源文件映射

热门文章

  1. sqlserver关于mirror镜像的总结
  2. 在Mac Os X 遇到不认识的汉字时,你可以这样做!教你输入生僻字
  3. 如何通过公众号的原始ID获取二维码?
  4. 【pycharm使用】【算数优先级】【变量的基本使用】【type` 函数查看变量类型】【变量的输入】【格式化输出】
  5. 无尽神域服务器维护,无尽神域突然显示数据包损坏怎么办 解决方案一览
  6. AutoCAD打印预览时显示空白
  7. Android打包的CPU架构
  8. 打卡第5天:安恒元旦杯-爆破鬼才续与linux shell
  9. caj文件打不开显示内存不足_(图文)手机内存不足怎么清理
  10. c#垂直投影法_第五套人民币10元和5元纸币采用了固定花卉水印和白水印,其中,白水印的特点是...