目录
一.二分查找(easy)
题目链接:704. 二分查找 - 力扣(LeetCode)
解法:
代码:
二.在排序数组中查找元素的第⼀个和最后⼀个位置(medium)
题目链接:34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
解法:
代码:
二分模板:
三.搜索插入位置(easy)
题目链接:35. 搜索插入位置 - 力扣(LeetCode)
解法:
代码:
四. x 的平方根(easy)
题目链接:69. x 的平方根 - 力扣(LeetCode)
解法:
代码:
五:山峰数组的峰顶(easy)
题目链接:852. 山脉数组的峰顶索引 - 力扣(LeetCode)
解法:
代码:
六:寻找峰值(medium)
题目链接:162. 寻找峰值 - 力扣(LeetCode)
解法:
代码:
七:搜索旋转排序数组中的最小值(medium)
题目链接:153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)
解法:
代码:
八:0〜n-1 中缺失的数字(easy)
题目链接:LCR 173. 点名 - 力扣(LeetCode)
解法:
代码:
一.二分查找(easy)
题目链接:704. 二分查找 - 力扣(LeetCode)
解法:
暴力解法无非就是从左到右枚举,复杂度O(N)
但是这个数组是一个升序的,如果随便取一个数比他小,那么所取得数左边的数都比目标小这样就只需要向他右边找,如果比目标值大也一样那么去它左边找。
- 定义 left , right 指针,分别指向数组的左右区间。
- 找到待查找区间的中间点 mid ,找到之后分三种情况讨论:
- arr[mid] == target 说明正好找到,返回 mid 的值;
- arr[mid] > target 说明 [mid, right] 这段区间都是⼤于 target 的,因此舍去右边区间,在左边 [left, mid -1] 的区间继续查找,即让 right = mid - 1 ,然后重复 2 过程;
- arr[mid] < target 说明 [left, mid] 这段区间的值都是⼩于 target 的,因此舍去左边区间,在右边 [mid + 1, right] 区间继续查找,即让 left = mid +1 ,然后重复 2 过程;
- 当 left 与 right 错开时,说明整个区间都没有这个数,返回 -1 。
代码:
二.在排序数组中查找元素的第⼀个和最后⼀个位置(medium)
题目链接:34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
解法:
暴力查找O(N)
二分:
查找左端点
- 左边区间 [left, resLeft - 1] 都是⼩于 x 的;
- 右边区间(包括左边界) [resLeft, right] 都是⼤于等于 x 的;
- 当我们的 mid 落在 [left, resLeft - 1] 区间的时候,也就是 arr[mid] < target 。说明 [left, mid] 都是可以舍去的,此时更新 left 到 mid + 1 的位置,继续在 [mid + 1, right] 上寻找左边界;
- 当 mid 落在 [resLeft, right] 的区间的时候,也就是 arr[mid] >= target 。说明 [mid + 1, right] (因为 mid 可能是最终结果,不能舍去)是可以舍去的,此时更新 right 到 mid 的位置,继续在 [left, mid] 上寻找左边界;
- 左指针: left = mid + 1 ,是会向后移动的,因此区间是会缩⼩的;
- 右指针: right = mid ,可能会原地踏步(⽐如:如果向上取整的话,如果剩下 1,2 两个元素, left == 1 , right == 2 , mid == 2 。更新区间之后, left,right,mid 的值没有改变,就会陷⼊死循环)。
循环条件:
求中点操作:
查找右端点
- 左边区间 (包括右边界) [left, resRight] 都是⼩于等于 x 的;
- 右边区间 [resRight+ 1, right] 都是⼤于 x 的;
- 当我们的 mid 落在 [left, resRight] 区间的时候,说明 [left, mid - 1]( mid 不可以舍去,因为有可能是最终结果) 都是可以舍去的,此时更新 left 到 mid的位置;
- 当 mid 落在 [resRight+ 1, right] 的区间的时候,说明 [mid, right] 内的元素是可以舍去的,此时更新 right 到 mid - 1 的位置;
- 左指针: left = mid ,可能会原地踏步(⽐如:如果向下取整的话,如果剩下 1,2 两个元素, left == 1, right == 2,mid == 1 。更新区间之后, left,right,mid 的值没有改变,就会陷⼊死循环)。
- 右指针: right = mid - 1 ,是会向前移动的,因此区间是会缩小的;
代码:
C++:
java:
二分模板:
三.搜索插入位置(easy)
题目链接:35. 搜索插入位置 - 力扣(LeetCode)
解法:
分析插入位置左右两侧区间上元素的特点:
- [left, index - 1] 内的所有元素均是小于 target 的;
- [index, right] 内的所有元素均是大于等于 target 的。
设 left 为本轮查询的左边界, right 为本轮查询的右边界。根据 mid 位置元素的信息,分析下⼀轮查询的区间:
- 当 nums[mid] >= target 时,说明 mid 落在了 [index, right] 区间上,mid 左边包括 mid 本⾝,可能是最终结果,所以我们接下来查找的区间在 [left,mid] 上。因此,更新 right 到 mid 位置,继续查找。
- 当 nums[mid] < target 时,说明 mid 落在了 [left, index - 1] 区间上,mid 右边但不包括 mid 本⾝,可能是最终结果,所以我们接下来查找的区间在 [mid+ 1, right] 上。因此,更新 left 到 mid + 1 的位置,继续查找。
直到我们的查找区间的⻓度变为 1 ,也就是 left == right 的时候, left 或者right 所在的位置就是我们要找的结果。
代码:
C++:
java:
四. x 的平方根(easy)
题目链接:69. x 的平方根 - 力扣(LeetCode)
解法:
- 如果 i * i == x ,直接返回 x ;
- 如果 i * i > x ,说明之前的⼀个数是结果,返回 i - 1 。

- [0, index] 之间的元素,平方之后都是小于等于 x 的;
- [index + 1, x] 之间的元素,平方之后都是大于 x 的。
代码:
C++:
java:
五:山峰数组的峰顶(easy)
题目链接:852. 山脉数组的峰顶索引 - 力扣(LeetCode)
解法:

- 峰顶数据特点: arr[i] > arr[i - 1] && arr[i] > arr[i + 1] ;
- 峰顶左边的数据特点: arr[i] > arr[i - 1] && arr[i] < arr[i + 1] ,也就是呈现上升趋势;
- 峰顶右边数据的特点: arr[i] < arr[i - 1] && arr[i] > arr[i + 1] ,也就是呈现下降趋势。
- 如果 mid 位置呈现上升趋势,说明我们接下来要在 [mid + 1, right] 区间继续搜索;
- 如果 mid 位置呈现下降趋势,说明我们接下来要在 [left, mid - 1] 区间搜索;
- 如果 mid 位置就是山峰,直接返回结果。

代码:
C++:
java:
六:寻找峰值(medium)
题目链接:162. 寻找峰值 - 力扣(LeetCode)
解法:
- arr[i] > arr[i + 1] :此时「左侧区域」⼀定会存在⼭峰(因为最左侧是负无穷),那么我们可以去左侧去寻找结果;
- arr[i] < arr[i + 1] :此时「右侧区域」⼀定会存在山峰(因为最右侧是负无穷),那么我们可以去右侧去寻找结果。
代码:
C++:
java:
七:搜索旋转排序数组中的最小值(medium)
题目链接:153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)
解法:
题目我们可以知道原本这个原本是一个升序数组,也即是
这个样子的一个数组,那么所谓的“旋转n次数”也就是所把最大的(数组最后)那几个值拿到前面去。
- 当 mid 在 [A,B] 区间的时候,也就是 mid 位置的值严格大于 D 点的值,下⼀次查询区间在 [mid + 1,right] 上;
- 当 mid 在 [C,D] 区间的时候,也就是 mid 位置的值严格小于等于 D 点的值,下次查询区间在 [left,mid] 上。
代码:
C++:
java:
八:0〜n-1 中缺失的数字(easy)
题目链接:LCR 173. 点名 - 力扣(LeetCode)
解法:
- 在第⼀个缺失位置的左边,数组内的元素都是与数组的下标相等的;
- 在第⼀个缺失位置的右边,数组内的元素与数组下标是不相等的。
代码:
C++:
java: