常用算法整理:二分查找
2016-04-09 16:30
405 查看
基础二分查找
二分查找是大家最常用的也是最简单的一种算法。二分查找在面试中是非常常见的一题,而且很多时候二分查找是时间效率最高的一种搜索方式。最简单的二分查找就是查找有序不重复数组中给定值的位置,基本模板如下:
var search = function(nums, target) { var s = 0, e = nums.length - 1, m; while(s+1<e) { m = parseInt((s+e)/2); if(nums[m] === target) { return m; } else if(nums[m] < target) { s = m; } else { e = m; } } if(nums[s] === target) return s; if(nums[e] === target) return e; return -1; };
这里一个技巧就是,为了防止不小心陷入无限循环,当两个指针相邻的时候即结束循环,然后需要判断下头指针和尾指针的值是否满足条件。
这个必须掌握,要写出bug free的代码,但是这个太简单了,所以实际出题的时候肯定不会直接出这么简单题目。
进阶二分查找
进阶二分查找题目依然是在有序数组中找到一个给定值,不过会出现一些变化,这里说几个经典的题目。第一种是搜索有重复的数组中第一个出现的或者最后一个出现的目标值的位置。
这里直接给一个综合的就是
Search for a range,在有重复的排序数组中找到指定值出现的范围,就要同时找到第一个出现的值和最后一个出现的值。
题目链接:https://leetcode.com/problems/search-for-a-range/
为了方便,这里我分成找第开头和找结束两步来进行:
var searchRange = function(nums, target) { var result = [-1,-1]; //找开头 var s = 0, e = nums.length-1, m; while(s+1<e) { m = Math.floor((s+e)/2); if(nums[m] >= target) { e = m; } else { s = m; } } if(nums[s] === target) result[0] = s; else if(nums[e] === target) result[0] = e; else return result; //找开头 s = 0, e = nums.length-1, m; while(s+1<e) { m = Math.floor((s+e)/2); if(nums[m] <= target) { s = m; } else { e = m; } } if(nums[e] === target) result[1] = e; else if(nums[s] === target) result[1] = s; return result; };
第二种,比较简单,叫
first bad version,就是说在
1~n个版本中有一个版本是错误的,然后给出了一个函数可以检测指定的版本是否有错误。
题目链接 https://leetcode.com/problems/first-bad-version/
这种题目就是二分查找的方式几乎没有难度,但是会有稍微一点变化,比如这一题就是认识到通过
isBadVersion函数来判断保留左边还是右边。
解法如下:
var solution = function(isBadVersion) { return function(n) { var s = 1, e = n, m; while(s+1<e) { m = Math.floor((s+e)/2); if(isBadVersion(m)) { e = m; } else { s = m; } } if(isBadVersion(s)) return s; if(isBadVersion(e)) return e; }; };
最后一个最难的个叫
Search in rotated sorted array,就是数组从某一个位置被翻转了一下,比如
[0,1,2,3,4,5]被翻转成了
[3,4,5,0,1,2]当然题目是不会告诉我们从哪里翻转的。那么我们有两个解法,一种是先通过二分查找找到翻转点,然后分别对左右两个有序数组进行二分查找,另外一个就是只用一次二分查找就可以解决,但是要注意移动指针的方式。
var search = function(nums, target) { var s = 0, e = nums.length-1, m; while(s+1<e) { m = parseInt((s+e)/2); if(nums[m] === target) return m; else if(nums[m] < nums[s]) { if(nums[m] <= target && target <= nums[e]) { s = m; } else { e = m; } } else { if(nums[m] >= target && target >= nums[s]) { e = m; } else { s = m; } } } if(nums[s] === target) return s; if(nums[e] === target) return e; return -1; };
解法如上, 这一题的要点就是确定指针应该如何移动,这里我们会通过比较
nums[s],nums[m],nums[e],target四个变量来确定如何移动指针,过程有点复杂但是基本原理就是确定target到底是在m的左边还是右边。
还有类似的比这个简单一些,只要找最小值 https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/
另外还有
sqrt,
find peak等题目。
相关文章推荐
- 搜狗百度360市值齐跌:搜索引擎们陷入集体焦虑?
- 本人即将筹备败家日志,敬请期待!
- 书评:《算法之美( Algorithms to Live By )》
- IE:使用搜索助手
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- C++二分查找在搜索引擎多文档求交的应用分析
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法