二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
1 | 示例 1: |
leetcode链接:二分查找
分析
这道题目的前提是数组为有序数组,同时还强调,数组中无重复元素,因为一旦有重复元素,使用二分查找返回的元素下标 可能不是唯一的。
所以使用二分法的前提条件:
- 有序,2. 数组中无重复值
二分法,掌握二分法的核心就是处理好二分法的边界条件,需要理解区间的定义。
写二分法,区间的定义一般分为两种:左闭右闭 [left,right] 或者 左闭右开 [left,right).
两种区间的定义,分别有两种不同的二分写法
第一种写法,左闭右闭
第一种写法,定义 target 是在一个 左闭右闭的区间里,也就是 [left,right]
区间的定义决定了二分法的边界,因为定义 target 在 [left,right],所以有如下两点:
- while(left <= right) ,要使用 <=, 因为 闭区间 包含 left 和 right,所以 left === right 是有意义的,要使用 <=
- if(nums[middle] > target),这时 right 要 赋值给 middle - 1, 因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
来个图例,辅助理解,比如 在 1,2,3,4,7,9,11 中查找 2。
代码如下
1 | const search = function(nums, target) { |
第二种写法,左闭右开
第二种写法 定义 target 在 左闭右开的区间里,也就是 [left, right), 那这个边界处理和左闭右闭区间边界处理方式截然不同
- while(left < right) 这里使用 < , 因为不包含 right ,所以 left === right 在 [left, right) 区间是没有意义的
- if(nums[mid] > target), right 更新为middle,因为当前 nums[mid] 不等于 target,去左区间继续寻找,而寻找区间是左闭右开区间,所以 right 更新为 mid, 下一次查找区间不会去比较 nums[mid]
还是在 1,2,3,4,7,9,11 中查找 2。如图所示 (注意和方法一的区别)
代码
1 |
|
总结
二分法核心就是处理好边界问题,容易出错的点就在于 在循环中没有始终坚持根据查找区间的定义来做边界处理。
其实区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。
本文介绍了二分法常见的两种区间定义 和 详细的分析。
总结成两点:
- 左闭右闭,循环终止条件 <=, 边界要等于 mid ➕ 1、 ➖1
- 左闭右开,循环终止条件 <,边界等于 mid。
与二分法相关题目如下,来练习下吧