mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-24 03:56:28 +00:00
build
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
<!-- 此文件由 utils/exercises/publish_exercises.py 根据 exercises.yaml 自动生成,请勿直接修改。 -->
|
||||
|
||||
# 10.7 练习
|
||||
|
||||
## 10.7.1 知识巩固
|
||||
|
||||
### 1. 二分查找怎样缩小搜索区间
|
||||
|
||||
在有序数组 `[2, 5, 8, 12, 16, 23, 38]` 中查找 16。
|
||||
使用双闭区间 `[i, j]`,中点为
|
||||
$m=i+(j-i)/2$(向下取整)。
|
||||
|
||||
请写出每轮的 `(i, j, m)`、中点元素,以及下一步如何缩小区间,
|
||||
直到找到目标。
|
||||
|
||||
??? success "参考答案"
|
||||
|
||||
每轮查找过程如下:
|
||||
|
||||
| 轮次 | `(i, j, m)` | 中点元素 | 下一步 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `(0, 6, 3)` | 12 | `12 < 16`,令 `i = 4` |
|
||||
| 2 | `(4, 6, 5)` | 23 | `23 > 16`,令 `j = 4` |
|
||||
| 3 | `(4, 4, 4)` | 16 | 找到目标,返回索引 4 |
|
||||
|
||||
数组有序,所以中点值小于目标时可以排除中点及其左侧;
|
||||
中点值大于目标时可以排除中点及其右侧。
|
||||
|
||||
### 2. 重复元素的左右边界
|
||||
|
||||
在数组 `[1, 2, 2, 2, 4, 6]` 中查找数字 2。
|
||||
一名同学用二分查找在索引 2 找到目标后立即返回,并说:
|
||||
“索引 2 就是数字 2 的左边界。”
|
||||
|
||||
<!-- numbered-subquestions -->
|
||||
|
||||
1. 这名同学的说法是否正确?数字 2 的左、右边界分别是多少?请说明理由。
|
||||
2. 查找左边界时,若中点元素等于目标,接下来应继续搜索哪一侧?
|
||||
3. 查找右边界时又应继续搜索哪一侧?只需说明方向,无须写出完整的查找过程。
|
||||
|
||||
??? success "参考答案"
|
||||
|
||||
1. 这名同学的说法不正确。找到一个 2 后立即返回,只能保证找到某一个 2,不能保证找到最左或最右的 2。
|
||||
本题的左边界为索引 1,右边界为索引 3。
|
||||
|
||||
2. 查找左边界时,即使中点元素等于 2,也要继续搜索左侧,
|
||||
例如在双闭区间写法中令 `j = m - 1`。
|
||||
|
||||
3. 查找右边界时,中点元素等于 2 后应继续搜索右侧,
|
||||
例如令 `i = m + 1`。
|
||||
|
||||
### 3. 不同数据该选哪种搜索方法
|
||||
|
||||
请在“顺序查找、二分查找、哈希表”中,为下面三个场景选择合适的方法,并说明理由:
|
||||
|
||||
<!-- numbered-subquestions -->
|
||||
|
||||
1. 在 $10^7$ 个已经有序且不再变动的整数中反复查找,不额外建立其他数据结构;
|
||||
2. 在频繁插入、删除的数据集中反复判断某个键是否存在,不要求保持有序,也不进行范围查找;
|
||||
3. 在无序数组中只查找一次某个值。
|
||||
|
||||
??? success "参考答案"
|
||||
|
||||
1. 二分查找:数据有序且静态,$O(\log n)$ 且无须额外空间。
|
||||
2. 哈希表:当哈希函数能把键较均匀地分散到各桶时,插入、删除和按键查找的平均时间复杂度都是 $O(1)$。
|
||||
3. 直接从头到尾遍历:只查找一次时,排序或建立哈希表都要先处理整个数组,
|
||||
并不会减少这一次任务的总工作量。
|
||||
|
||||
选择取决于数据是否有序、是否允许建立额外结构、查询次数以及需要执行哪些操作。
|
||||
|
||||
## 10.7.2 编程练习
|
||||
|
||||
### 1. 有序数组的二分查找
|
||||
|
||||
给定一个按严格递增顺序排列的整数数组 `nums` 和目标值 `target`。请使用二分查找找到 `target`:若存在,返回它的数组索引;若不存在,返回 -1。
|
||||
|
||||
??? tip "解题提示"
|
||||
|
||||
1. 初始区间是 left = 0、right = n - 1,非空条件是 left <= right
|
||||
2. 用 mid = left + (right - left) // 2 计算中点
|
||||
3. 若 `nums[mid]` 小于 `target`,就把左边界移到 `mid + 1`;若 `nums[mid]` 大于 `target`,就把右边界移到 `mid - 1`;相等时立即返回
|
||||
|
||||
[LeetCode](https://leetcode.cn/problems/binary-search/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } [题目解析](https://leetcode.cn/problems/binary-search/solutions/1692151/by-jyd-i7xr/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }
|
||||
|
||||
### 2. 有序数组的插入位置
|
||||
|
||||
给定一个按严格递增顺序排列的整数数组 `nums` 和目标值 `target`。
|
||||
|
||||
若 `target` 已在数组中,返回它的索引;否则,返回把 `target` 插入数组后仍能保持严格递增顺序的位置。答案可能是 0,也可能等于数组长度。请使用二分查找。
|
||||
|
||||
??? tip "解题提示"
|
||||
|
||||
1. 答案可能是 0,也可能是数组长度 n
|
||||
2. 使用双闭区间时,若 `nums[mid]` 大于等于 `target`,就令 `right = mid - 1`,继续检查更靠左的位置;否则令 `left = mid + 1`
|
||||
3. 循环结束时 left 就是插入位置
|
||||
|
||||
[LeetCode](https://leetcode.cn/problems/search-insert-position/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }
|
||||
@@ -21,3 +21,4 @@ icon: material/text-search
|
||||
- [10.4 哈希优化策略](replace_linear_by_hashing.md)
|
||||
- [10.5 重识搜索算法](searching_algorithm_revisited.md)
|
||||
- [10.6 小结](summary.md)
|
||||
- [10.7 练习](exercises.md)
|
||||
|
||||
Reference in New Issue
Block a user