c++ - 跳跃二分搜索有直观的解释吗?
问题描述
我正在阅读《竞技程序员手册》:https ://cses.fi/book/book.pdf
在第 32 页及以上(PDF pp 42)中,提到了二分搜索的方法 2,我不确定我是否完全理解。然后他们稍微修改它以找到最小值,使得函数 ok() 为真,并尝试在数组中找到最大值。我不直观地理解这里发生了什么。有什么直观的解释吗?
int k = 0;
for (int b = n/2; b >= 1; b /= 2) {
while (k+b < n && array[k+b] <= x) k += b;
}
if (array[k] == x) {
// x found at index k
}
找到适用于函数 ok 的最小值
int x = -1;
for (int b = z; b >= 1; b /= 2) {
while (!ok(x+b)) x += b;
}
int k = x+1;
求先增后减函数的最大值
int x = -1;
for (int b = z; b >= 1; b /= 2) {
while (f(x+b) < f(x+b+1)) x += b;
}
int k = x+1;
解决方案
书中的解释非常好!我将以它们为起点。
假设您有一本字典,您在第一页 ( int k = 0;
) 上打开它,然后您正在字典中查找一个单词 ( x
)。
不变的假设是:
- 字典中的单词按非递减顺序排列(对于每个
i
, 0 <i
<n
:array[i-1]
<=array[i]
), - 您当前正在查看的单词( )
array[k]
永远不会大于您正在查找的单词( <array[k]
=x
始终为真)。
b
是您对离答案还有多少页的猜测。在二分搜索中,您总是猜测最大可能距离的一半。最初,最大可能的距离是字典的长度n
。因此,最初,您将字典长度的一半作为您的猜测 - int b = n/2;
。
您可以将当前位置移动k
到猜测的页数之前b
,即只要假设 2. 得到满足。然后你再次猜测,将你猜测的距离减半b
。
当b
变为 1 时,您在字典中找到了您一直在寻找的页面。要么array[k] == x
- 字典包含 page 上的单词k
,要么你的字典中没有这样的单词。
后面带有 和 的例子与带有 的例子!ok(x+b)
基本f(x+b) < f(x+b+1)
相同array[k+b] <= x
。
想象一下,您有一个数组,其中包含 in 的所有可能值!ok(i)
(array[i]
或 in 的所有可能值f(i) < f(i+1)
)array[i]
。然后你用array
与 相同的方式进行二进制搜索array[k+b] <= x
。
请注意,本书假定ok(i)
并f(i)
适用于 any i
,而数组大小是有限的并且必须检查:k+b < n
,n
数组大小在哪里。
书中代码风格注意事项:
在竞争性编程中,您有非常有限的时间来解决大量算法问题并且不再查看代码,可以使用短变量名,没有注释等。看到许多#DEFINE
指令也很常见 -参见例如https://gist.github.com/kodekracker/e09f9d23573f117a5db0。
我明白这可能非常令人惊讶。在长期专业项目的世界中,为了实现速度而交易代码可读性是不可接受的。
推荐阅读
- javascript - 跨 Karma 单元测试和 Protractor 端到端测试共享的测试库
- excel - 条件格式 - if 和语句
- php - 我在这个文件中有 index.php 当我尝试用 css 设置样式时有 html 没有影响
- r - Rstudio 不会在断点处停止
- excel - 搜索 DAX 公式 - 相当于 Excel SUMIF
- jquery - jquery:在滚动时更改 css
- ios - UITableView 滚动时跳动闪烁
- codenameone - 属性的 setLabel 导致 NPE
- c++ - 没有构造函数的类对象的动态分配
- mongodb - Mongo DB,如何在匹配查询中选择所有文档?