「二分查找」之我见!今天刷一道leetcode算法!
来自:码农田小齐
算法将是我今后更新的重点,因为我个人非常喜欢。。而且面试考它啊!有人说刷题没有用,但是你做了题就能感受到 coding 能力的提升和对语言熟悉度的提升。新的一年,每日一题,我们一起进步一起NB!
今天第一题选了我最喜欢的也是折磨了我很久的但并不算难的题目,最终是因为在 GS 电面中被问到了,我才痛下决心把这类题目一网打尽。
先来看最基本版的题目:Leetcode 153题
题干是给了一个【本来排好序了的 且为升序】的数组,然后又在某个不知道的位置旋转了一下,所谓旋转,就是把前面那堆数移到后面来了,求新数组的最小值。比如:
原 array:[0, 1, 2, 4, 5, 6, 7]
rotate 之后就是:[4, 5, 6, 7, 0, 1, 2]
输出:最小值 0
解法一:
Brute Force 暴力解法就是每个数都过一遍,然后用一个变量记录我们见到过的最小值并随时更新。(这个应该都会吧,不会的话可以后台留言告诉我。。请让我看到你。。)
Time complexity = O(n),因为每个数都过了一遍;
Space complexity = O(1),因为只用了有限几个变量。
解法二:
在 O(n) 的基础上我们还想优化,那方向是 O(logn),再想想查找类算法的很容易想到了 binary search。
binary search 的做法就是每轮排除一半,留下另一半是包含正确答案的,再不断缩小范围,把答案找出来。那么解决的关键就在于如何杀掉这一半而不能把答案误杀了。中文叫二分查找,我认为翻译的挺好的,因为只有一次分两份,去掉一份,才能保证时间复杂度是 O(logn)。(此处不懂可以后台留言给我,我会根据反馈在之后的文章补充。)
那么二分查找题目的考点就在于如何排除掉这一半了,一般是通过比较中间的数和左右两端或者目标值的关系,但没有统一的规律,否则还考啥?只能多见多去领悟其精髓,我会在更新完所有 binary search 的题目之后做个总结。
就这一题来说,我们比较 array[mid] 和 array[left] or array[right] 的大小关系,哪边都行。
方法一、先看和右边的比较
如果 array[mid] > array[right],如下图例子,7 比 2 要大,这是不正常的(不升序)的,说明最小值在右边,所以排除左边以及 mid(array[mid] 已经比 array[right] 大了,不可能为最小值),所以
left = mid + 1;
如果 array[mid] < array[right](没有=,因为没有duplicates),说明右边是 sorted 的,说明最小值在左边甚至可能就是 mid 本身,所以
所以 right = mid。
while终止条件是 left == right 的时候,此时 mid = left = right,返回nums[left] = nums[right] 都行。
// Java
class Solution{public int findMid(int[] nums) {if(nums == null || nums.length == 0) {return -1; // discuss with interviewer}int left = 0;int right = nums.length - 1;while(left < right) {int mid = left + (right - left)/2;if(nums[mid] > nums[right]) {left = mid + 1;} else {right = mid;}}return nums[left];}
}
/*
Runtime: 0 ms, faster than 100.00% of Java online submissions for Find Minimum in Rotated Sorted Array.
Memory Usage: 38.5 MB, less than 79.54% of Java online submissions for Find Minimum in Rotated Sorted Array.
*/
方法二、再看和左边比较
如果 array[mid] >= array[left](这里可能=,因为 mid 可能就是 left;而 mid 不可能是 right,因为 Java 向0取整且如果 left = right 就跳出循环了),那么左边是 sorted 的,最小值在右边(题目说一定 rotated 了),所以 left = mid + 1,但有两点要注意:
注意⚠️:最小值有可能就是 left,虽然最初数组是 rotate 了,但是在减半之后有可能就是完整 sorted 的
所以此方法还要加一步:最开始先判断是否是sorted的,即array[left] vs array[right]
注意⚠️:array[mid] = array[left] 时,只剩2个元素,且上一步判断过了这2个元素并非升序,所以最小值是 array[right],所以需要移动 left = mid+1。和 right 比较不需要,因为 mid 不会等于 right。
如果 array[mid] < array[left],那么右边是 sorted 的,最小值在左边甚至是 mid 本身,所以 right = mid。
while loop 条件同上
// Java
class Solution {public int findMid(int[] nums) {int left = 0;int right = nums.length - 1;while(left < right) {if(nums[left] < nums[right]) { //⚠️return nums[left];}int mid = left + (right - left)/2;if(nums[mid] >= nums[left]) { //⚠️left = mid + 1;} else {right = mid;}}return nums[left];}
}
/*
Runtime: 0 ms, faster than 100.00% of Java online submissions for Find Minimum in Rotated Sorted Array.
Memory Usage: 38.6 MB, less than 77.27% of Java online submissions for Find Minimum in Rotated Sorted Array.
*/
这题说完了。
Follow up 是154题,可能有 duplicates 的情况。大家可以稍作思考再往下看。
基本思路和上一题一样,但是 [3, 3, 1, 3] 不work,因为当 mid = right 时,无法判断最小值到底在哪边,所以只能一步步走,worst case O(n) 避免不了。
// Java
class Solution {public int findMin(int[] nums) {int left = 0;int right = nums.length - 1;while(left < right) {int mid = left + (right - left)/2;if(nums[mid] > nums[right]) {left = mid + 1;} else if (nums[mid] == nums[right]) {right --;} else {right = mid;}}return nums[left];}
}
/*
Runtime: 0 ms, faster than 100.00% of Java online submissions for Find Minimum in Rotated Sorted Array II.
Memory Usage: 41.8 MB, less than 6.25% of Java online submissions for Find Minimum in Rotated Sorted Array II.
*/
以上就是 rotate array 中找最小值的完整方法了,明天我们来看在 rotate array 中找一个特定目标值的题目,这题有很多方法,我会分享我认为觉得最好的一种,会对 binary search 的理解更加深刻。
题目:Leetcode 33 & 81
特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:长按订阅更多精彩▼如有收获,点个在看,诚挚感谢
「二分查找」之我见!今天刷一道leetcode算法!相关推荐
- 去掉数组最后一个元素_leetcode 34. 在排序数组中查找元素的第一个和最后一个位置每天刷一道leetcode算法系列!...
作者:reed,一个热爱技术的斜杠青年,程序员面试联合创始人 前文回顾: leetcode1. 两数之和--每天刷一道leetcode系列! leetcode2. 两数相加--每天刷一道leetcod ...
- leetcode17. 电话号码的字母组合--每天刷一道leetcode算法系列!
作者:reed,一个热爱技术的斜杠青年,程序员面试联合创始人 前文回顾: leetcode1. 两数之和--每天刷一道leetcode系列! leetcode2. 两数相加--每天刷一道leetcod ...
- 常用十大算法 非递归二分查找、分治法、动态规划、贪心算法、回溯算法(骑士周游为例)、KMP、最小生成树算法:Prim、Kruskal、最短路径算法:Dijkstra、Floyd。
十大算法 学完数据结构该学什么?当然是来巩固算法,下面介绍了十中比较常用的算法,希望能帮到大家. 包括:非递归二分查找.分治法.动态规划.贪心算法.回溯算法(骑士周游为例).KMP.最小生成树算法:P ...
- 二分查找基础概念与经典题目(Leetcode题解-Python语言)二分数值型
二分查找的讲解请见上一篇文章.本文主要记录对数值进行二分的题目解法与思路. 374. 猜数字大小 class Solution:def guessNumber(self, n: int) -> ...
- 二分查找基础概念与经典题目(Leetcode题解-Python语言)二分索引型
二分查找的定义如下(引自Wiki): 在计算机科学中,二分查找算法(英语:binary search algorithm),也称折半搜索算法(英语:half-interval search algor ...
- 无序链表(顺序查找)和有序数组(二分查找)-基础实现-符号表(二)-数据结构和算法(Java)
文章目录 1 无序链表的顺序查找 1.1 无序链表实现 1.2 分析 2 有序数组中的二分查找 2.1 实现 2.2 分析 3 对二分查找的分析 4 总结 5 后记 1 无序链表的顺序查找 1.1 无 ...
- 算法学习 |从无到有 刷爆LeetCode算法神器
开始文章输出之前,我没有着急下笔,而是认真的问了自己几个问题. 我为什么要学算法? 如何保持学习的热情和积极性? 学到的算法是否可以应用到工作中? 学到的算法怎么应用到工作中? 如何实现从掌握到精通? ...
- 根可达算法的根_好屌好屌的「GC系列」JVM垃圾定位及垃圾回收算法浅析
0x01 什么是垃圾 很简单,没有引用指向的任何对象都叫做垃圾(garbage). 什么是garbage 在某一内存空间中,Java程序制造了很多对象被引用,有的对象还引用别的对象,中途有对象不被需要 ...
- leetcode2. 两数相加--每天刷一道leetcode系列!
来自:程序员面试 作者:reed,一个热爱技术的斜杠青年,程序员面试联合创始人 题目描述 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节 ...
最新文章
- Terracotta tc-config.xml配置说明(这个真的是转的)
- 记录一下VsCode配置C/C++运行环境
- WIN32 使用 MUTEX 实现禁止多开
- booloader编写
- 210326阶段三人脸识别
- 我喜欢的一首歌--《幸福的瞬间》
- C++/C 宏定义(define)中# ## 的含义(转)
- 智能会议系统(32)---WebRTC学习之三:录音和播放
- msys 中打开系统程序
- 视频APP软件开发功能架构
- 用HTML+CSS做一个漂亮简单的个人网页——樱木花道篮球3个页面 学生个人网页设计作品 学生个人网页模板 简单个人主页
- Error occurred during initialization of VM 解决
- html验证座机号码_JS校验手机号 座机 邮箱 微信号
- 《以幽默的方式过一生》总结1——春
- 解决UE4打包Android报错app:packageDebug FAILED的一个土方法
- Zookeeper 3.5.7学习记录(一)——集群的坑
- oa系统服务器租赁,oa服务器租赁
- 隐匿的风暴,Saas海啸正瞄准企业IT业务
- 自身知识浅薄,开发积累问题
- 记录一下:老衲的py路程 mac下的tkinter小应用