mirror of
https://github.com/krahets/hello-algo.git
synced 2026-05-03 19:12:30 +08:00
build
This commit is contained in:
@@ -16,10 +16,10 @@ comments: true
|
||||
|
||||
如图 10-2 所示,我们先初始化指针 $i = 0$ 和 $j = n - 1$ ,分别指向数组首元素和尾元素,代表搜索区间 $[0, n - 1]$ 。请注意,中括号表示闭区间,其包含边界值本身。
|
||||
|
||||
接下来,循环执行以下两个步骤:
|
||||
接下来,循环执行以下两步。
|
||||
|
||||
1. 计算中点索引 $m = \lfloor {(i + j) / 2} \rfloor$ ,其中 $\lfloor \space \rfloor$ 表示向下取整操作。
|
||||
2. 判断 `nums[m]` 和 `target` 的大小关系,分为三种情况:
|
||||
2. 判断 `nums[m]` 和 `target` 的大小关系,分为以下三种情况。
|
||||
1. 当 `nums[m] < target` 时,说明 `target` 在区间 $[m + 1, j]$ 中,因此执行 $i = m + 1$ 。
|
||||
2. 当 `nums[m] > target` 时,说明 `target` 在区间 $[i, m - 1]$ 中,因此执行 $j = m - 1$ 。
|
||||
3. 当 `nums[m] = target` 时,说明找到 `target` ,因此返回索引 $m$ 。
|
||||
@@ -334,7 +334,7 @@ comments: true
|
||||
|
||||
时间复杂度为 $O(\log n)$ 。每轮缩小一半区间,因此二分循环次数为 $\log_2 n$ 。
|
||||
|
||||
空间复杂度为 $O(1)$ 。指针 `i` , `j` 使用常数大小空间。
|
||||
空间复杂度为 $O(1)$ 。指针 $i$ 和 $j$ 使用常数大小空间。
|
||||
|
||||
## 10.1.1 区间表示方法
|
||||
|
||||
@@ -633,12 +633,12 @@ comments: true
|
||||
|
||||
## 10.1.2 优点与局限性
|
||||
|
||||
二分查找在时间和空间方面都有较好的性能:
|
||||
二分查找在时间和空间方面都有较好的性能。
|
||||
|
||||
- 二分查找的时间效率高。在大数据量下,对数阶的时间复杂度具有显著优势。例如,当数据大小 $n = 2^{20}$ 时,线性查找需要 $2^{20} = 1048576$ 轮循环,而二分查找仅需 $\log_2 2^{20} = 20$ 轮循环。
|
||||
- 二分查找无须额外空间。相较于需要借助额外空间的搜索算法(例如哈希查找),二分查找更加节省空间。
|
||||
|
||||
然而,二分查找并非适用于所有情况,原因如下:
|
||||
然而,二分查找并非适用于所有情况,主要有以下原因。
|
||||
|
||||
- 二分查找仅适用于有序数据。若输入数据无序,为了使用二分查找而专门进行排序,得不偿失。因为排序算法的时间复杂度通常为 $O(n \log n)$ ,比线性查找和二分查找都更高。对于频繁插入元素的场景,为保持数组有序性,需要将元素插入到特定位置,时间复杂度为 $O(n)$ ,也是非常昂贵的。
|
||||
- 二分查找仅适用于数组。二分查找需要跳跃式(非连续地)访问元素,而在链表中执行跳跃式访问的效率较低,因此不适合应用在链表或基于链表实现的数据结构。
|
||||
|
||||
@@ -13,10 +13,10 @@ status: new
|
||||
|
||||
回忆二分查找插入点的方法,搜索完成后 $i$ 指向最左一个 `target` ,**因此查找插入点本质上是在查找最左一个 `target` 的索引**。
|
||||
|
||||
考虑通过查找插入点的函数实现查找左边界。请注意,数组中可能不包含 `target` ,此时有两种可能:
|
||||
考虑通过查找插入点的函数实现查找左边界。请注意,数组中可能不包含 `target` ,这种情况可能导致以下两种结果。
|
||||
|
||||
1. 插入点的索引 $i$ 越界;
|
||||
2. 元素 `nums[i]` 与 `target` 不相等;
|
||||
- 插入点的索引 $i$ 越界。
|
||||
- 元素 `nums[i]` 与 `target` 不相等。
|
||||
|
||||
当遇到以上两种情况时,直接返回 $-1$ 即可。
|
||||
|
||||
@@ -334,9 +334,9 @@ status: new
|
||||
|
||||
### 2. 转化为查找元素
|
||||
|
||||
我们知道,当数组不包含 `target` 时,最后 $i$ , $j$ 会分别指向首个大于、小于 `target` 的元素。
|
||||
我们知道,当数组不包含 `target` 时,最终 $i$ 和 $j$ 会分别指向首个大于、小于 `target` 的元素。
|
||||
|
||||
根据上述结论,我们可以构造一个数组中不存在的元素,用于查找左右边界,如图 10-8 所示。
|
||||
因此,如图 10-8 所示,我们可以构造一个数组中不存在的元素,用于查找左右边界。
|
||||
|
||||
- 查找最左一个 `target` :可以转化为查找 `target - 0.5` ,并返回指针 $i$ 。
|
||||
- 查找最右一个 `target` :可以转化为查找 `target + 0.5` ,并返回指针 $j$ 。
|
||||
@@ -345,7 +345,7 @@ status: new
|
||||
|
||||
<p align="center"> 图 10-8 将查找边界转化为查找元素 </p>
|
||||
|
||||
代码在此省略,值得注意的有:
|
||||
代码在此省略,值得注意以下两点。
|
||||
|
||||
- 给定数组不包含小数,这意味着我们无须关心如何处理相等的情况。
|
||||
- 因为该方法引入了小数,所以需要将函数中的变量 `target` 改为浮点数类型。
|
||||
|
||||
@@ -227,7 +227,7 @@ status: new
|
||||
|
||||
此方法虽然可用,但其包含线性查找,因此时间复杂度为 $O(n)$ 。当数组中存在很多重复的 `target` 时,该方法效率很低。
|
||||
|
||||
现考虑拓展二分查找代码。如图 10-6 所示,整体流程保持不变,每轮先计算中点索引 $m$ ,再判断 `target` 和 `nums[m]` 大小关系:
|
||||
现考虑拓展二分查找代码。如图 10-6 所示,整体流程保持不变,每轮先计算中点索引 $m$ ,再判断 `target` 和 `nums[m]` 大小关系。
|
||||
|
||||
1. 当 `nums[m] < target` 或 `nums[m] > target` 时,说明还没有找到 `target` ,因此采用普通二分查找的缩小区间操作,**从而使指针 $i$ 和 $j$ 向 `target` 靠近**。
|
||||
2. 当 `nums[m] == target` 时,说明小于 `target` 的元素在区间 $[i, m - 1]$ 中,因此采用 $j = m - 1$ 来缩小区间,**从而使指针 $j$ 向小于 `target` 的元素靠近**。
|
||||
@@ -447,6 +447,6 @@ status: new
|
||||
|
||||
本节的代码都是“双闭区间”写法。有兴趣的读者可以自行实现“左闭右开”写法。
|
||||
|
||||
总的来看,二分查找无非就是给指针 $i$ , $j$ 分别设定搜索目标,目标可能是一个具体的元素(例如 `target` ),也可能是一个元素范围(例如小于 `target` 的元素)。
|
||||
总的来看,二分查找无非就是给指针 $i$ 和 $j$ 分别设定搜索目标,目标可能是一个具体的元素(例如 `target` ),也可能是一个元素范围(例如小于 `target` 的元素)。
|
||||
|
||||
在不断的循环二分中,指针 $i$ , $j$ 都逐渐逼近预先设定的目标。最终,它们或是成功找到答案,或是越过边界后停止。
|
||||
在不断的循环二分中,指针 $i$ 和 $j$ 都逐渐逼近预先设定的目标。最终,它们或是成功找到答案,或是越过边界后停止。
|
||||
|
||||
@@ -6,7 +6,7 @@ comments: true
|
||||
|
||||
「搜索算法 searching algorithm」用于在数据结构(例如数组、链表、树或图)中搜索一个或一组满足特定条件的元素。
|
||||
|
||||
根据实现思路,搜索算法总体可分为两种:
|
||||
搜索算法可根据实现思路分为以下两类。
|
||||
|
||||
- **通过遍历数据结构来定位目标元素**,例如数组、链表、树和图的遍历等。
|
||||
- **利用数据组织结构或数据包含的先验信息,实现高效元素查找**,例如二分查找、哈希查找和二叉搜索树查找等。
|
||||
|
||||
Reference in New Issue
Block a user