今天回归了力扣的周赛,第一题完成之后,发现第二题是对第一题的性能优化。我的第一反应就是使用二分查找实现性能的优化。
二分查找的边界问题虽然以前已经搞清楚过,但是一段时间不用之后就又开始模糊了☠️,我决定写一篇文章,相当于是备忘录吧,记录一下二分查找的简单使用。(其实也是最近想尝试一下写博客来记录自己的学习之路😁)
边界问题
首先就是边界问题了,这边的边界指什么呢?
指的是left和right
注意:我所使用的方法是左闭右闭的方法
左闭右闭代表什么呢?
代表在查找的时候,left是可以取到的,right也是可以取到的。下面我写一下二分查找的一个经典模板,我会再重点的地方加上注释方便理解。
代码举例
下方代码的作用是,给定一个升序排序的
nums数组,需要查找数组中是否target元素,有则返回其对应下标,没有则返回-1。 这道题其实就是力扣的第704题:leetcode.cn/problems/bi… 大家可以去练练手。
let left = 0
let right = nums.length - 1// 注意 此处数组的长度减去 1 是为了实现左闭右闭, 使得right可以取到,即nums[right]合法。
// 注意 下方while条件中,是要写 left <= right 还是 left < right 呢?
//这个时候只需要思考我们的 "左闭右闭" 的查找范围中, left <= right 的情况是否是合法的。
//比如我取一个数组的范围是 "[3, 3]" 这代表我取数组的下标为3的元素,这明显是符合条件的。
//所以此处需要写left <= right
while (left <= right) {
let mid = Math.floor((left + right) / 2)
if (nums[mid] > target) {
// 注意 此处为什么不是 right = mid 呢?
// 因为我们的边界是左闭右闭的,所以在上次查找的时候,边界也是查找的范围,已经被查找过了
// 所以我们这个时候直接略去mid即可,下面的一个 else if 分支也是同理的
right = mid - 1
} else if (nums[mid] < target) {
left = mid + 1
} else {
return mid
}
}
return -1
总结
下面总结一下全部的内容,以后如果记忆模糊了可以直接看下面的内容✌️✌️
- 将搜索范围设置成
左闭右闭 - while 循环内的条件设置成
left <= right,因为在左闭右闭的范围中进行搜索,类似于[3, 3]的搜索范围是合理的,它代表范围是下标为3的元素。 - while 循环内的 if 判断中,当出现
nums[mid] > target的情况下,需要将执行的操作设置为right = mid - 1,原因是在左闭右闭的边界中,上一轮的查询已经将mid也放入了查询的范围中了,没有必要将mid对应的下标再放入下一轮的查询中。
希望以上的内容对你有所帮助。😉