【LeetCode】剑指 Offer 11. 旋转数组的最小数字
【LeetCode】剑指 Offer 11. 旋转数组的最小数字
文章目录
- 【LeetCode】剑指 Offer 11. 旋转数组的最小数字
- 一、遍历
- 二、二分法
- 总结
一、遍历
算法步骤:
- 遍历数组,只要后一个数大于前一个数就说明最小的数还在后面,找到后一个数小于前一个数就说明找到了
- 如果遍历完数组还是没有找到,那就说明后面每一个数都大于第 1 个数,因此第一个数是最小数
class Solution {public int minArray(int[] numbers) {int i = 0;while(i < numbers.length - 1 && numbers[i+1] >= numbers[i]){i++;}if(i+1 >= numbers.length){return numbers[0];}return numbers[i+1];}
}
二、二分法
思路与算法
一个包含重复元素的升序数组在经过旋转之后,可以得到下面可视化的折线图:
其中横轴表示数组元素的下标,纵轴表示数组元素的值。图中标出了最小值的位置,是我们需要查找的目标
我们考虑数组中的最后一个元素 x:在最小值右侧得元素,他们的值一定都小于等于 x;而在最小值左侧的元素,它们的值一定都大于等于 x。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值
在二分查找的每一步中,左边界为 low,右边界为 high,区间的中点为 pivot,最小值就在该区间内。我们将中轴元素 numbers[pivot] 与右边界元素 numbers[high] 进行比较,可能会有以下的三种情况:
第一种情况是 numbers[pivot] < numbers[high]。如下图所示,这说明 numbers[pivot] 是最小值右侧的元素,因此我们可以忽略二分查找区间的右半部分
第二种情况是 numbers[pivot] > numbers[high]。如下图所示,这说明 numbers[pivot] 是最小值左侧的元素,因此我们可以忽略二分查找的区间的左半部分
第三种情况是 numbers[pivot] == numbers[high]。如下图所示,由于重复元素的存在,我们并不能确定 numbers[pivot] 究竟在最小值的左侧还是右侧,因此我们不能莽撞地忽略某一部分的元素。我们唯一可以知道的是,由于它们的值相同,所以无论 numbers[high] 是不是最小值,都有一个和它值相同的 numbers[pivot],因此我们可以忽略二分查找区间的右端点
当二分查找结束时,我们就得到了最小值所在的位置
class Solution{public int minArray(int[] numbers){int low = 0;int high = numbers.length - 1;while(low < high){int pivot = low + (high - low) / 2;if(numbers[pivot] < numbers[high]){high = pivot;} else if(numbers[pivot] > numbers[high]){low = pivot + 1;} else{high -= 1;}}return numbers[low];}
}
- 时间复杂度:平均时间复杂度为 O(logn),其中 n 是数组 numbers 的长度。如果数组是随机生成的,那么数组中包含相同元素的概率很低,在二分查找的过程中,大部分情况都会忽略一半的区间。而在最坏情况下,如果数组中的元素完全相同,那么 while 循环就需要执行 n 次,每次忽略区间的右端点,时间复杂度为 O(n)
- 空间复杂度:O(1)
总结
翻了翻题解的评论区,不得不感叹一下,即使你解出来了,但是没有用最优的解法,这道算法题在面试官眼里真的就是 0 分!这次我太急了,2 分钟就想出遍历的方法,就直接提交了。回想我第一次做 leetcode 的题时,俩小时没有解出一道简单题,把四大查找,八大排序都复习了一边,像从中找到灵感,但是这一次题目很明显是查找,我却没有深入思考,我本应该想到四大查找的,该死!
class Solution {public int minArray(int[] numbers) {if(numbers.length == 1){return numbers[0];}int mid = (numbers.length - 1) / 2;int i = mid;while(i < numbers.length - 1 && numbers[i+1] >= numbers[i]){i++;}if(i == numbers.length - 1 &&numbers[i] > numbers[0]){return numbers[0];}if(i+1 <= numbers.length - 1){return numbers[i+1] > numbers[0]?numbers[0]:numbers[i+1]; }i = mid;if(i == 0){return numbers[0] > numbers[1]?numbers[1]:numbers[0];}if(numbers[i] < numbers[i-1]){return numbers[i];}i = mid;while(i > 1 && numbers[i-1] <= numbers[i]){i--;}return numbers[i];}
}
这是我自己在得知要使用二分法后写的,用了很多判断语句,很复杂。虽然二分查找是要在一个有序的数组里查找,但是我感觉这一道题也是可以二分更多次的,但是又看到要进行那么多次的复杂判断,又感觉不行,最后看了的题解,果然是可以一直进行二分的,而且代码整体也要比我的简洁。看了题解的思路,发现是我将问题的情况划分得太多了,有的情况可以划分为一类,从而减少判断语句,对于学过的知识还是要活学活用啊
【LeetCode】剑指 Offer 11. 旋转数组的最小数字相关推荐
- Leetcode 剑指 Offer 11. 旋转数组的最小数字 (每日一题 20210916)
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转, ...
- leetcode剑指 Offer 11. 旋转数组的最小数字(二分查找)
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转, ...
- 《LeetCode力扣练习》剑指 Offer 11. 旋转数组的最小数字 Java
<LeetCode力扣练习>剑指 Offer 11. 旋转数组的最小数字 Java 一.资源 题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 给你一个可能存在 ...
- 剑指 Offer 11. 旋转数组的最小数字 简单
剑指 Offer 11. 旋转数组的最小数字 题目 解题思路 方法(一)直接遍历法 方法(二)二分查找法 题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组 ...
- 剑指offer 11. 旋转数组的最小数字(很详细!)
剑指offer 11. 旋转数组的最小数字 题目 解题思路 代码 题目 解题思路 一开始,我们就能直接想到,数组找最小值,那么不轻轻松松直接遍历一遍,用一个变量记录最小值,然后直接返回不就完事了? 但 ...
- 【剑指 Offe】剑指 Offer 11. 旋转数组的最小数字
目录标题 算法汇总 题目 关键点 代码 1.解体方法 - 二分法 思路 代码 时间和空间复杂度 2.解题方法,如暴力法 思路 代码 时间和空间复杂度 算法汇总 以下是所有算法汇总,包括GitHub源码 ...
- 剑指offer——11.旋转数组的最小数字
题目: 题1:实现快速排序 题2:年龄排序问题. 题3:旋转数组的最小数字 知识点: 快速排序算法,参考:https://blog.csdn.net/shujuelin/article/details ...
- 剑指 Offer 11. 旋转数组的最小数字 LCOF
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转, ...
- 【双百解法】剑指 Offer 11. 旋转数组的最小数字
立志用最少的代码做最高效的表达 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如,数组 [3,4,5,1,2] 为 [1 ...
最新文章
- 一文详解C++文件读写(FileStorage、txt)
- TIOBE 9 月排行榜:C++ 式微,第 3 名被 Python 拿下
- python第三十课--异常(raise关键字)
- larvare数据库引入php_PHP全栈学习笔记6
- WebDriver API 元素定位(三)
- SLAM - 01 - 分类
- WPF(Windows Presentation Foundation)用户界面框架
- 数据分析对企业的重要性
- android sdk的封装,Android封装SDK的使用
- 【电脑讲解】硬件知识
- android条码扫描串口,串口条码扫描器的正确安装方法[图解]
- windows下格式化内存卡
- WebRTC收集网卡地址信息 源码剖析
- python-flask 设置网页保留缓存静态文件时间
- 剖析SPDK读写NVMe盘过程--从hello_world开始
- 用树莓派搭建远程下载+私有云盘(中篇)
- Android开发——Snackbar使用详解
- pip 更换国内安装源 阿里源 清华源 豆瓣源等等
- InnerClass annotations are missing corresponding EnclosingMember annotations. Such InnerClas...
- 优化Windows xp Professional大全
热门文章
- php 购物车案例教程,php初步实现购物车功能的实例分析
- 华为大数据战略_任正非:华为应抓住“大数据”机遇 抢占战略制高点
- grafana官方使用文档_5. Centos7 下部署使用 nmon2influxdb
- java中Jackson_java 中的好东西 jackson
- python入门题目及答案_Python基础知识的一些练习与解答,python,部分,习题,及,答案...
- kubernetes ConfigMap和Secret:配置应用程序
- 动态排名系统(整体二分)
- 一个整数,它加上100后是一个完全平方数,加上168又是一个完全平方数,请问该数是多少?...
- The Largest Clique UVA - 11324( 强连通分量 + dp最长路)
- zoj 1676Network Wars(胡博涛论文题,01分数规划+最小割)