一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
前言
每天一道算法题,手撕算法
今天可能有的朋友注意到了,我们的题目变了,变成ts,不是js,其中的原因也很简单,主要是我ts比较菜,所以为了成为一个ts菜鸟,坚持使用ts做题,要不连成为ts菜鸟的资格都没有🤣
今天我们来学习二分查找,其实二分查找并不难,但是主要是细节方面,还有就是我们如何才能把二分查找真正的记住呢?这也是我们今天要探索的
题目
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
题解
思考
对于查找类的题目来说,使用二分查找时间复杂度无疑是最快的O(logn)
我们先来上二分查找的模板,模板在手,天下我有
function binarySearch(nums:number[],target:number):number{
let left:number = 0;
// 这里如果-1,那么while条件中就会有等于,没有-1,那就没有等于
let right:number = nums.length-1;
// while是循环中花费时间最好的方法,不容反驳
while(left<=right){
// 这里是关键中的关键,也就是二分的核心,就是找一个中间数,这个取中间数的操作一定要记住,记住他,那么你就记住了这个模板的80%
let mid:number = left+Math.floor((right-left)/2);
if(nums[mid] === target){
return mid;
// 因为mid已经搜索过,应该从搜索区间中去除**。
}else if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}
}
return -1;
}
我们的模版定义的right为target.length-1; while(left<=right)
可能有的同学会问为什么不取target.length;while(left<right),因为他会漏掉一个数,比如left和right都为2的时候他就会报错,这样子就会漏掉2没有参与比较,所以我们不用这个
题解
function search(nums: number[], target: number): number {
let left:number =0;
let right:number = nums.length-1;
while(left<=right){
let mid:number = left+Math.floor((right-left)/2);
if(target===nums[mid]){
return mid;
}else if(target<nums[mid]){
right = mid - 1;
}else if(target>nums[mid]){
left = left+1;
}
}
return -1;
};
总结
二分查找写完了,怎么样,感觉还是很简单的吧!但是我们如何记住呢,总不能每天都来复习一遍吧。这里我们引用labuladong大师的二分搜索升天词,来进行记忆
搜索一个元素时,搜索区间两端闭。
while条件带等号,否则需要打补丁。
if相等就返回,其他的事甭操心。
mid必须加减一,因为区间两端闭。
while结束就凉凉,凄凄惨惨返-1。
这诗句真是朗朗上口,方便记忆,再次感谢labuladong大师