《冬训周报五》
写在前面
马上要回校了,这两期就写一些总结,后续有要补充的再进行修改,因为写的都是自己常用的,并不是知识性科普在做题的过程中我发现自己还是有一些基本算法和基础结构不太熟练,在此先给自己做一个基本算法的总结。
在此写的基本算法有排序、二分、贪心。(后续进行算法补充)
(本文只是阐述个人看法,以及参考部分资料)
排序
常用的就是sort函数,sort()极大地节省了我在刷题过过程中所花费的时间,sort()函数是类似快速排序的方法,时间复杂度为n*log2(n),执行效率高。
在前面也有一起我写了结构体排序也是用到了sort(),可见sort()函数是很灵活的。
关于sort()函数的头文件,是#include<algorithm>,(不过我一般都是用万能头文件,这里也是搜了下才知道的)
sort的基本用法
sort的基本用法:它有三个参数sort(begin, end, cmp)
,其中begin为指向待sort()的数组的第一个元素的指针
,end为指向待sort()的数组的最后一个元素的下一个位置的指针
,cmp参数为排序准则,cmp参数可以不写,如果不写的话,默认从小到大进行排序。
自定义规则
关于sort()函数,我们是可以自定义排序规则的,《冬训周报三》里提到的结构体排序就是这样排序的,自定义排序规则,以便满足不同的排序情况,比如说按照每个数从大到小排序,
需要我们写一个cmp函数作为排序规则传到sort()函数中。
定义的cmp函数规则为:
bool cmp(int x,int y){ return x % 10 > y % 10; }
然后将cmp函数传入sort()函数中即可实现排序需求。
#include<iostream> #include<algorithm> using namespace std; bool cmp(int x,int y){ return x % 10 > y % 10; }
int main(){ int num[10] = {65,59,96,13,21,80,72,33,44,99}; sort(num,num+10,cmp); for(int i=0;i<10;i++){ cout<<num[i]<<" "; }//输出结果:59 99 96 65 44 13 33 72 21 80 return 0; }
了解了规则再进行排序很多时候就会方便很多。
二分
什么是二分
到底什么是二分呢?二分二分就是一分为二。简单来说二分就是在有序序列中,通过不断的二分,进而不断地缩小范围去寻找满足我们条件的解。这只是对二分一个狭义上的理解,广义二分其实是如果有一个临界值使得临界值一边的数据满足一种性质,另一边满足另一种性质,即使不是有序的但也可以利用二分去寻找这个临界值。
二分算是一个我还算常用到的吧,有些时候数据太大的时候就会想到使用二分,不然就会TLE。
多余的话就不再阐述了,二分也分为二分查找和二分答案。
二分查找
二分查找还是好理解的,就是在数轴的两端分为[l, mid] 和 [mid+1, r]两部分,直到最后找到l=r的值,直接给出二分查找的模板吧
// 将区间分为[L,mid],[mid+1,R] bool check(mid){//判断条件函数 } //终止条件是left==right while(left<right){ int mid=(left+right)>>1;//这里使用右移运算主要是在负数时右移向下取整,除法向零取整 if(check(mid)) right=mid;//判断如果mid这个值满足[L,mid]这个区间里面的的数的性质,则将r=mid,缩小范围 else left=mid+1; //否则另l=mid+1,+1的原因是mid不满足条件不能取 } cout<<left; // 将区间分为[L,mid-1],[mid,R] while(left<right){ int mid=(left+right+1)>>1;//这里一定要加1!原因稍后再讲 if(check(mid)) left=mid;//判断如果mid这个值满足[mid,R]这个区间里面的的数的性质,则将l=mid,缩小范围 else right=mid-1; //否则另r=mid-1,+1的原因是mid不满足条件不能取 } cout<<left;
总结:该模板保证最终答案处于闭区间[l,r]以内,循环以l=r结束,每次二分的中间值mid会归属于左半段与右半段二者之一,优点是几乎可以用于所有的二分题型,但缺点是需要分清楚两种情况,并根据实际情况选择相应的模板。
二分答案
说实话我自己对这个还是不太清楚的,可能也是刷过的题比较少,不过在二分查找和二分答案相比二分答案显然是更重要的,主要这类题也很难从问题本身去找到答案,这类问题通常用于答案的值域已经确定,这样就可以从答案值域入手,判定这个值符不符合题目要求,根据判定结果缩小范围从而找到最优值。
大体上可以有三个类别:
①求满足条件的最大(小)值
②最大值最小化问题
③最小值最大化问题
贪心
在我看来,贪心算法更像是找最优解,就像是在有限时间内如何赚更多钱,有限空间内如何装更多有价值的东西,和动态规划,01背包那种很相似,但又不太相同。
我又查了一下,发现大佬对于贪心是这样定义的:
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
理解起来有点抽象,先记录一下,时不时再来回顾一下 从零开始学贪心算法
emm总的说,贪心就是选取某种策略求出当前最优解,而又不是从整体考虑。
贪心算法的步骤
①建立数学模型来描述问题 。
②把求解的问题分成若干个子问题 。
③对每个子问题求解,得到子问题的局部最优解。
④把子问题的解局部最优解合成原来解问题的一个解 。
贪心的优势即是省去了枚举所有情况而要耗费的大量时间,更加快速。
这步骤说实话单看的话还是有点难理解。
如果不知道怎么分析可以看下大佬的是如何分析的