文章目录
前言
一、二分查找法[整数]
1.例题:AcWing 789. 数的范围
2.本题代码:
(1)本题核心部分详解:
(2)AC代码:
二、二分查找法[浮点数]
1.例题:AcWing 790. 数的三次方根
2.AC代码:
三、二分查找的代码模板:
1.整数二分:
2.浮点数二分模板:
四、时间复杂度的分析:
前言
复习acwing算法基础课的内容,本篇为讲解基础算法:二分,关于二分查找法的时间复杂度的分析,以后会补充到本博客中,目前先鸽了,对于题目的代码不做过多解释,二分查找中每一行代码的详细见二分查找的模板
一、二分查找法[整数]
1.例题:AcWing 789. 数的范围
这里结合具体的习题去讲解二分,并且给出代码模板:二分例题的链接:AcWing789.数的范围
本博客给出本习题的截图:
2.本题代码:
代码如下:
(1)本题核心部分详解:
/* 写之前明确自己要求什么 假设查找x的坐标,本题输出中的第一个数为≥x的最小位置,第二个输出为≤x的最大位置 如果没有该元素就输出“-1 -1” 对于查找≥x的最小位置: */ int l = 0, r = n - 1; //题意从0开始为起始坐标,故终点坐标为n - 1 while(l < r) { int mid = l + r >> 1 //等同于 mid = (l + r) / 2; if (q[mid] >= x) //q[mid]就是二分后的最中间的数 //q[mid]如果≥x,我们要找的是≥x的最小位置 //即我们要找的位置在mid的左边或就是mid(当只有一个数的时候) r = mid; //故我们要更新r,使得r = mid; else //即q[mid] < x,而我们要找的是≥x的数,即要找的在mid的右边 l = mid + 1; //故更新l为mid + 1 } /* 此时我们的l,或者是r就是我们要找的起始坐标 输出起始坐标还有一个问题:如何保证我们真正的找到了这个数 */ if (q[l] != x) printf("-1 -1"); //如果我们真正的找到了这个数,那么我们的q[l]或是q[r]应该是等于我们要查找的数字x的 //所以有该if语句,即如果不等于的话,就输出"-1 -1" //接下来去查找≤x的最小位置: int l1 = 0, r1 = n - 1; //这里的l1我们可以从0开始,也可以从l开始 while (l < r) { int mid = l + r + 1 >> 1; //等同于 mid = (l + r + 1) / 2 //至于这里为什么要写成(l + r + 1) / 2,见代码模板 if (q[mid] <= x) //q[mid]如果≤x,我们要找的是≤x的最大位置 //即我们要找的位置在mid的右边或就是mid(当只有一个数的时候) l = mid; //故我们要更新l,使得l = mid; else //即q[mid] > x,而我们要找的是≤x的数,即在mid的左边 r = mid - 1; //故更新r为mid - 1 }
(2)AC代码:
#include <iostream> using namespace std; const int N = 100010; int q[N]; int main() { int n, m; cin >> n >> m; for (int i = 0; i < n; i ++ ) cin >> q[i]; while (m -- ) { int k; cin >> k; int l = 0, r = n - 1; while (l < r) { int mid = l + r >> 1; if (q[mid] >= k) r = mid; else l = mid + 1; } if (q[l] != k) cout << "-1 -1" << endl; else { cout << l << ' '; int l1 = 0, r1 = n - 1; while (l1 < r1) { int mid = l1 + r1 + 1 >> 1; if (q[mid] <= k) l1 = mid; else r1 = mid - 1; } cout << r1 << endl; } } return 0; }
二、二分查找法[浮点数]
1.例题:AcWing 790. 数的三次方根
例题连接:数的三次方根
本博客给出本习题的截图:
2.AC代码:
代码如下:
#include <iostream> using namespace std; int main() { double x; cin >> x; double l = -10000, r = 10000; //因为要通过二分去求,左右端点直接赋值成题目中给定的n的范围边界 while (r - l > 1e-8) //当所求l和r十分接近的时候,即可求出³√x的值 //题目中要求保留6位小数,故这里写成1e-8最为保险(高题目要求2个精度) //即题目若要求四位小数的话,写成1e-6,以此类推 { double mid = (r + l) / 2; if (mid * mid * mid >= x) r = mid; //证明³√x ≤ mid,即所求在mid左边,故 r = mid else l = mid; } printf("%.6lf", l); return 0; }
三、二分查找的代码模板:
本模板来自AcWing的y总-算法基础课,AcWing链接:AcWing
1.整数二分:
bool check(int x) {/* ... */} // 检查x是否满足某种性质 //以下为y总总结的两个代码模板,可选择任何一个进行记忆,注意区别两个代码的不同 //背下下来拿任何一个就足够了; int bsearch_1(int l, int r) { while (l < r) { int mid = l + r >> 1; //等同于 mid = (l + r) / 2; if (check(mid)) r = mid; // check()判断mid是否满足性质 else l = mid + 1; } return l; } // 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用: int bsearch_2(int l, int r) { while (l < r) { int mid = l + r + 1 >> 1; if (check(mid)) l = mid; //如果更新为 l = mid,则上一行需要补上+ 1,即mid = l + r + 1 >> 1 //如果更新如 bsearch_1 中的r = mid则不需要补 + 1 //具体原因y总上课有将,没有太理解什么意思,索性不求甚解 //这里可以先记住 是否补充 + 1取决于更新后是r = mid还是l = mid,后者需要补 + 1 //具体为什么需要补充 + 1,后续理解了会更新说明。 else r = mid - 1; } return l; }
2.浮点数二分模板:
bool check(double x) {/* ... */} // 检查x是否满足某种性质 double bsearch_3(double l, double r) { const double eps = 1e-8; // eps 表示精度,取决于题目对精度的要求(要比题目要求的高2个精度) while (r - l > eps) { double mid = (l + r) / 2; if (check(mid)) r = mid; else l = mid; } return l; }
四、时间复杂度的分析:
博主自己还没搞懂,先鸽了,日后一定补齐时间复杂度和证明。