我正在阅读《竞争程序员手册》:https://cses.fi/book/book.pdf
在第32页及以上(PDF pp 42)上,提到了二进制搜索方法2,我不确定我是否完全理解。然后,他们对其稍加修改以找到最小值,以使函数ok()为true,然后尝试在数组中找到最大值。我不直观地了解这里发生了什么。有什么直观的解释吗?
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;
答案 0 :(得分: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;
。
只要可以,即只要满足假设2,就将当前位置k
移到页面b
的猜测数之前。然后您再次猜测,将猜测距离b
减半。
当b
变为1时,您已经在所需的字典中找到该页面。 array[k] == x
-词典包含页面k
上的单词,或者词典中没有此类单词。
后面带有!ok(x+b)
和f(x+b) < f(x+b+1)
的示例与带有array[k+b] <= x
的示例基本相同。
想象一下,您有一个数组,其中包含!ok(i)
中array[i]
的所有可能值(或f(i) < f(i+1)
中array[i]
的所有可能值)。然后,以与array
相同的方式对array[k+b] <= x
进行二进制搜索。
请注意,该书假定ok(i)
和f(i)
适用于任何i
,而数组大小是有限的,必须检查:k+b < n
,其中{{1 }}是数组大小。
请注意本书中的代码样式:
在竞争性编程中,您只有很有限的时间来解决大量算法问题,并且再也不需要看代码,因此可以使用短变量名,不加注释等形式。许多n
指令-例如参见https://gist.github.com/kodekracker/e09f9d23573f117a5db0。
我知道这可能会令人惊讶。在长期专业项目的世界中,为了实现速度而以极大的可读性交易代码是不可接受的。