欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

90%的程序员都写错的算法-二分查找万能模版

发布时间:2025/3/19 编程问答 34 豆豆
生活随笔 收集整理的这篇文章主要介绍了 90%的程序员都写错的算法-二分查找万能模版 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

新的角度看二分

  • 二分就是将数组分为两段
  • 因此,问题的最终目标是找出蓝红边界

朴素算法

  • 红色指针一开始指向最右超出范围处,随后不断向左移动,直到找到蓝红边界;或者蓝色指针…
  • 时间复杂度O(n)O(n)O(n)

二分查找


  • 红蓝指针的移动其实代表着红蓝区域的拓展。那么,有什么更快拓展的方式呢?由于数组本身有序…便可以快速拓展红色 或 蓝色区域
  • 数组下标有效范围[0,n−1][0,n - 1][0,n1],因此,初始时l = -1, r = n;
  • 循环的结束条件是l + 1 != r,因为l指向蓝色边界最右边,r指向红色边界最左边,当l + 1 == r时整个数组已经由灰色未知被划分完毕
  • 如果m是红色区域,直接r = m;同理…
  • 最后结果返回l还是r要看情况

细节1.为什么l的初始值为-1,r的初始值为n

  • 假如最终整个数组都该是红色区域,如果l初始化为0,l一开始就处在红色区域内,这会造成错误;同理…

细节2.m是否始终处于[0,n)以内

  • 只有处在这个区间以内,m才是有意义的
  • 先看m的下界,由于m = (l + r) / 2(向下),因此如果我们想让m尽可能小,就要l和r尽可能小,l的最小值是初始值-1,r如果能进入循环体,最小值是1(不是0),因此m最小值为0
  • 再看m上界,同理,r的最大值为n,l如果要进入循环体,最大值为n - 2,因此m最大值为n - 1

细节3.更新指针时,能不能写成l = m + 1或者r = m - 1


  • 如果刚好m指向蓝色区域的最后一个位置,l如果变为m + 1,就错了;同理…

细节4.会不会陷入死循环

  • 分别考虑l + 1 == r l + 2 == r l + 3 == r的情况
  • l + 1 == r,退出循环
  • l + 2 == r,也就是它们之间隔一个元素,当进入循环体时,m就是它们之间隔着的那个元素,接下来,要么将l设置成m,要么将r设置成m,也就是说,在循环体结束时,l的下一个元素一定是r,会回归到第一种情况并退出循环体
  • l + 3 == r,会回归到第二种情况或者回归到第一种情况

例子 与 c++库函数

  • lower_bound对应大于等于
  • upper_bound对应大于

一般流程

  • 后处理指的是 例如 只有蓝色区域/红色区域的返回值处理问题(需要特判)等

如果没有蓝色区域或者红色区域

  • 那么l或者r会不在有效范围内
  • 最后结果特判,l的初始值为-1,r的初始值为n

浮点数的二分

  • 题目 :通过二分查找的方式计算2\sqrt{2}2,要求误差小于10−610^{-6}106
  • 退出循环的条件为r - l <= 1e-8
  • 要求误差小于10−610^{-6}106,相当于 结果保留6位小数;这样,循环退出的条件是10−810^{-8}108,而输出则是六位小数
#include <iostream> #include <iomanip> using namespace std; int main() {double l = -10000, r = 10000;while (r - l > 1e-8){double mid = (l + r) / 2;if (mid * mid >= 2) r = mid;else l = mid;} // printf("%.6lf\n", l);cout << fixed << setprecision(6) << l << endl;return 0; }

总结

以上是生活随笔为你收集整理的90%的程序员都写错的算法-二分查找万能模版的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。