(坚持每天都写算法)算法基础复习part1基础算法1-4——二分
1.(坚持每天都写算法)算法基础复习part1基础算法1-2——归并排序2.(坚持每天都写算法)算法基础复习part1基础算法1-1——快排3.(坚持每天都写算法)算法基础复习part1基础算法1-3
4.(坚持每天都写算法)算法基础复习part1基础算法1-4——二分
5.(坚持每天都写算法)算法复习与学习part1基础算法1-56.(坚持每天写算法)算法复习与学习part1基础算法1-6——高精度加法7.(坚持每天写算法)基础算法复习与学习part1基础算法1-7——高精度减法(处理t=1和t>1代码的写法,t为操作次数)8.(坚持每天都写算法)算法复习与学习part1基础算法1.8高精度乘法9.(坚持每天写算法)算法复习和学习part1基础算法part1-9高精度乘法10.(坚持每天写算法)算法学习与复习part1基础算法part1-10——前缀和11.(坚持每天写算法)算法复习与学习part1基础算法part1-11——差分12.(坚持每天写算法)算法复习与学习part1基础算法part1-12——双指针算法13.(坚持每天写算法)算法学习与复习part1基础算法1-13——位运算14.(坚持每天写算法)算法复习和学习part1基础算法part1-14——离散化二分使用的前提是有序性的条件如果要找以下情况:
1.找大于等于数的第一个位置
2.找小于等于数的第一个位置
二分使用的前提是无序性的条件下如果要找以下情况:
1.找最大值
2.找最小值
二分法一般有边界问题,如果是有序性的条件下的话只要记住一句话:有加必有减。
这里是示例代码:
int mid = l + r + 1 (加)>> 1; if (check(mid)) l = mid; else r = mid - 1 (减);
然后这里是另一例代码:
int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1;
第一个代码命名为SR,第二个代码名为SL,如果是情况1,那么就用SR,如果是情况2,那么就使用SL。
二分法找最值,运用到了递归,使用递归分割数组获得某两数组(只有一个元素也可以算作数组,只不过代码是if条件)的最值,比较得出较大的值,作为该两个数组合体后的数组的最值,一直这样下去直到合成的数组是题目给出的数组。
这里是代码:
int process(int* a,int L,int R){ //L是该段数据的左边界 //R是该段数据的右边界 if(L == R) return *(a+L); int mid = L+((R-L)/2);//计算中点 int Leftmax = process(a,L,mid); int Rightmax = process(a,mid+1,R); return (Leftmax>Rightmax)?Leftmax:Rightmax; }
(如果有点看不懂代码可以思考以下二叉树的左右上排序,递归都是可以画递归树的,画一下就行了)
这里我搬以下别人的图解,很清晰的。
其实今天想记录的是一道题,使用的二分,顺便把二分写一下。
这里是代码:
//寻找范围,直接使用查找 //check(mid)是查找条件,一定要知道查找条件 //本人习惯 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int N = 100010; int a[N]; int left_bound(int l , int r , int x){ //l和r相等了就不用再找了 while(l < r){ int mid = l + r >> 1;//左边界,如果r=l + 1 且条件为真,那么更新后可以变成[r,r] , 靠近左边 if(a[mid] >= x) r = mid;//因为都大于等于了,即证明还没有到目标值,所以直接等于mid就行了 else l = mid + 1;//一步步缩减范围,r会凑近左边,如果中间数小于x,那么l就会尝试去mid的右边(可能等于,也可能正好大于,大于的话就要输出-1-1了 } return l; } int right_bound(int l , int r , int x){ while(l < r){ int mid = l + r + 1 >> 1;//右边界, 如果 r = l + 1 ,且条件为真,靠近右边 if(a[mid] <= x ) l = mid;//倒过来了,原理和上面的一样 else r = mid - 1;//因为是有边界嘛,所以要-1,好凑近右边界,得到目标值 } return r;//这里肯定是r,其实l也可以,但是按照逻辑来看还是r好 } int main(){ int n , q; cin >> n >> q; for(int i = 0 ; i < n ; i ++) cin >>a[i]; while(q --){ int k ; cin >>k; int begin = left_bound(0 , n -1 , k); if(a[begin] != k) cout << "-1 -1" << endl; else cout << begin << " " << right_bound(0 , n - 1 , k) << endl; //endl是空行符号,中间的“ ” 是空格 } return 0; }
时间复杂度:每一次都找中间,2^k = n ,所以k = log2_N(就算加了span元素那个N还是在下一行,使用markdown的公式也没法显示,所以就直接这么显示了),即时间复杂度是O(logn)。
本文作者:程序计算机人
本文链接:https://www.cnblogs.com/clina/p/17955406
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步