Files
hsa/Html/apps/static/68bacdfadf5aeae0912f7f18-第四章:查询-二分查找.html
2025-11-13 20:15:53 +08:00

112 lines
5.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- 你的其他样式 -->
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script>
MathJax.config = {
tex: {
inlineMath: [['$', '$'], ['\(', '\)']]
},
svg: {
fontCache: 'global'
}
};
</script>
</head>
<body>
<h1>二分查找</h1>
<h2>二分查找</h2>
<h3>二分查找的原理</h3>
<p>二分查找是一个基础但很重要的知识点,也是一种特殊的分治,为以后许多高级的数据结构与算法铺垫。</p>
<p>下面是一个用二分的简单场景:</p>
<p>假设小明从0到1000之间选择了一个数字但不告诉你你可以不断猜测这个数每次猜测小明会告知你的猜测得过大还是过小问最多几次就一定能猜中</p>
<p>答案是利用二分查找的原理猜测11次即可。</p>
<ol>
<li>对于0到1000的答案备选区猜测中位数500假设过小</li>
<li>则对于501到1000的答案备选区猜测750假设过大</li>
<li>则对于501到749的答案备选区猜测625假设过小</li>
<li>则对于626到749区间......</li>
<li>688-749</li>
<li>718-749</li>
<li>734-749</li>
<li>742-749</li>
<li>746-749</li>
<li>748-749</li>
<li>749-749</li>
</ol>
<p>在最差的情况下第11次的答案备选区就一定长度为1了也就是必然是答案。</p>
<p>因此如果序列是有序的,就可以通过二分查找快速定位所需要的数据。</p>
<h4>例题</h4>
<p>对于上面那个题目如果问题区间是1到4000最差情况下需要猜测几次这个值可以怎么迅速地算出来你可以用时间复杂度的公式建立一下并推导一下么</p>
<h3>练习:二分查找</h3>
<p>试试对于下面的题目,用代码实现一下二分查找。</p>
<h4>题目:有序数组寻址</h4>
<p>给出一个长度为n的有序数组从小到大有q次询问对于每次询问输出指定数在数组中的下标。如果不存在则输出-1。</p>
<h5>输入</h5>
<p>第一行一个整数n。(1&lt;=n&lt;=10^5)</p>
<p>第二行n个用空格分开的整数ai。(0&lt;=ai&lt;=10^8)</p>
<p>第三行一个整数q表示询问的次数。(1&lt;=q&lt;=10^4)</p>
<p>后q行每行一个整数b表示询问的数。(0&lt;=b&lt;=10^8)</p>
<h5>输出</h5>
<p>q行每行一个整数对应每次询问的返回结果</p>
<h5>提示:</h5>
<p>完成代码后通知Agent进行评测。</p>
<p>如果你还不完全会这个算法询问Agent获取提示并进行学习。</p>
<h3>二维二分查找</h3>
<h4>二分查找的直觉</h4>
<p>通过之前的原理和实现,二分查找本质上是通过取中的方式,尽可能排除多(一半)的备选数。
<br>
为进一步理解,除了序列,本节我们来尝试一下在矩阵(二维数组)上进行分治和查找。</p>
<h4>问题建模</h4>
<p>给出一个n*n的矩阵其中每一行都是一个从小到大的序列每一列都是从小到大的序列。从中找到指定的一个数target。</p>
<h5></h5>
<p>[
[1, 2, 4, 5]
[2, 5, 7, 11]
[3, 8, 10, 12]
[4, 10, 17, 20]
]
从中找到&quot;8&quot;这个数。</p>
<h5>线性做法</h5>
<p>这里先介绍线性做法。
一维序列的线性做法就是逐个比对一下,
二维做法最差是逐个扫描n*n所有的数可以聪明一些降低到线性成本称为“楼梯式”查找</p>
<ol>
<li>从右上角看一个元素 x = M[r][c]</li>
<li>查找与排除
a. 若 x &gt; target则这一列里 x 下方都 ≥ x更不可能是 target所以安全地左移排除一整列
b. 若 x &lt; target则这一行里 x 左边都 ≤ x更不可能是 target所以安全地下移排除一整行</li>
<li>持续直到排除所有行和列,从而找到目标元素或告知找不到。</li>
</ol>
<p>做法正确性分析,时间复杂度分析。</p>
<h4>分治做法:二维二分</h4>
<p>接下来试着通过二分的技术,找找复杂度更低的做法。
试着回答这些问题并与AI教师进行讨论</p>
<ol>
<li>分解中点在哪里?</li>
<li>二分后排除掉的部分是哪些?</li>
<li>如何划分子问题?</li>
<li>时间复杂度是多少?</li>
</ol>
<h3>二维二分查找实现</h3>
<h4>题目:有序矩阵查找</h4>
<p>给出一个 n×n 的矩阵,其中每一行的元素都按照从小到大的顺序排列,每一列的元素也都按照从小到大的顺序排列。现需要判断指定的数 target 是否在该矩阵中,若存在则输出其所在的行下标和列下标(行和列均从 0 开始计数);若不存在则输出 - 1 -1。</p>
<h4>输入</h4>
<p>第一行一个整数 n。(1&lt;=n&lt;=10^3)
接下来 n 行,每行 n 个用空格分开的整数,表示矩阵的元素。
最后一行一个整数 target表示需要查找的数。</p>
<h4>输出</h4>
<p>一行两个整数,分别表示 target 所在的行下标和列下标,中间用空格隔开。若不存在则输出 - 1 -1。</p>
<h4>示例</h4>
<p>输入41 2 4 52 5 7 113 8 10 124 10 17 208
输出2 1</p>
</body>
</html>