基础算法笔记
文章平均质量分 51
基础算法以及模板
_Koto
温顺的菜鸡
展开
-
二分求LIS及证明
最长上升子序列的动态规划朴素做法为O(n2)O(n^{2})O(n2)贪心做法O(nlogn)O(nlog n)O(nlogn):假如在长度同为k的子序列中,要在后面接a[i]a[i]a[i]肯定优先接在长度为k,并且结尾最小的子序列上,这样的扩展性最好,这样维护一个每次都是最小结尾的子序列,一定是单调的。反证法证明:假如长度为3的子序列的结尾比长度为2的结尾小,长度为3前面的子序列的结尾一定比长度为2的子序列的结尾小,这样就会产生冲突; 由于这个序列是单调的,则可以使用二分每次找到比即将插入的数字x小原创 2021-05-17 21:49:12 · 300 阅读 · 1 评论 -
树状数组基础知识
树状数组用于快速处理区间问题;时间复杂度为logn树状数组可以将长度为n的数组分解成logn个区间;把n用二进制表示出来,n=2p1+2p2+…+2pm;其中m=logn;长度为2p1的区间:[1,2p1];长度为2p2的区间:[2p1+1,2p1 +2p2];…长度为2pm的区间:[2p1+2p2+…+1,2p1 +…2pm];若区间以x结尾,则长度为lowbit(x);用代码表示为:while(x){ printf("[%d,%d]\n",x-lowbit(x)+1,x); x-原创 2021-04-05 14:32:46 · 146 阅读 · 0 评论 -
常用数据结构持续更新
1.链表/*链表测试*//*int类型*/#include<bits/stdc++.h>using namespace std;struct node{ int key; node *next;//指向下一个节点};typedef node *ptrnode;typedef ptrnode List;typedef ptrnode pos;int isempty(List L){//判空函数 return L->next==NULL;}in原创 2021-03-03 21:22:08 · 224 阅读 · 1 评论 -
图论
1.拓扑排序一个有向无环图一定存在拓扑序,从入度为0的点开始遍历,每次遍历到下一个点的时候删去这条边,直到入度为0;int h[N],e[N],ne[N],idx;int d[N],path[N],t=0;//path用于存储拓扑序,d存储入度;int n,m;void add(int a,int b){//邻接表头插法 e[idx]=b; ne[idx]=h[a]; h[a]=idx++;}bool topsort(){ queue<int>a;原创 2021-01-25 00:20:59 · 159 阅读 · 0 评论 -
数论
1.质数1.质数的判定:bool fun(int n){ for(int i=2;i<=n/i;i++) if(n/i==0) return false; return true;}枚举到n/i既可以优化速度也可以有效防止溢出。2.分解质因数:一个数n最多有一个质因数大于sqrt(n);void fun(int n){ for(int i=2;i<=n/i;i++){//枚举2到sqrt(n); if(n%i==0){//i原创 2021-01-16 18:55:44 · 292 阅读 · 0 评论 -
动态规划
动态规划实质上时枚举出每种状态然后找出最优解;枚举一般用循环或者递归来实现:1.斐波那契数列要计算第n项的值就必须计算出n-1和n-2的值,计算n-1,必须先计算出n-2和n-3的值,一直到1和2为止;int fun(int n){ if(n==1) return 1; if(n==2) return 2; return fun(n-1)+fun(n-2);}画出图像之后会发现有大量的重叠子问题,这些重叠子问题可以避免重复计算,使用一个数组把已经计算过的值存储起来,需原创 2021-01-11 15:50:02 · 276 阅读 · 0 评论 -
树与图的遍历
深度优先遍历:树可以说属于无向图,通常使用邻接表来存储,在每一个节点处开一个链表,存储着跟他相连的节点的边。图的遍历(深度优先):每个节点只需要遍历一次,可以开一个数组用来记录状态;有向图的遍历(详解)#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;const int N=1e5+10,M=N*2;in原创 2021-01-07 23:07:57 · 119 阅读 · 0 评论 -
dfs&bfs
1.dfs深度优先搜索:常用递归实现,先画出递归树,深度优先指的是按照一条路线一直走到头,然后回溯,在回溯过程中还要检查是否有其他路径,如果有则继续走:1.全排列问题:枚举并记录记录每个数字的状态,对已经使用过的数字做标记int p[N],s[N];int m;void dfs(int n){ if(n==m){//终止条件 for(int i0;i<n;i++) printf("%d ",p[i]);//输出 puts(""); return; } for(int i=1;原创 2021-01-05 21:33:57 · 120 阅读 · 0 评论 -
哈希表——笔记
哈希表哈希表的主要作用是把一个非常大的集合映射到一个比较小的集合中,建立哈希表需要一个hash函数,一般的操作就是取模;许多个非常大的数字对一个比较小的数字取模之后容易发生冲突,也就是容易出现重复;常用的解决冲突的方法有拉链法,1.拉链法,就是在对应的hash值下面接一个链表,链表中存储的是原来的数字。链表建议使用数组实现的链表;例如将一些非常大的数字存储在一个大小为1e5的数组中,(建立hash表时,取模的数字最好是质数,这样可以降低出现冲突的概率)具体操作:哈希表使用数组实现,下标就原创 2021-01-04 21:37:03 · 156 阅读 · 0 评论 -
堆——笔记
堆堆是一种二叉树的的结构,并且满足一个节点存储的值必须小于他的两个子节点这种关系 堆的大致模型存储方式:可以使用一维数组来存储一颗二叉树;比如节点x,他的两个子节点分别是2x和2x+1。注意这里x的下标是从1开始,从0开始的话2*0仍然是0;根据这个规则,堆可以进行以下的操作:1.寻找最小值 也就是树根;2.插入一个元素,在堆的末尾插入,然后再根据堆的排序规则放置到合适的位置;3.删除最小值,因为使用一维数组存储,所以删除最小值时无法直接删除,可以将末尾的值把最小值覆盖掉,然后再将末尾原创 2021-01-04 14:47:30 · 98 阅读 · 0 评论 -
并查集笔记
学习笔记1.并查集:** 作用**:用于快速判断元素是否在一个集合中,或者合并两个集合的数据结构;原理:使用树结构来存储元素:每个节点x的父节点为p[x],所以树根节点x的父节点还是x;1.判断树根:`if(p[x]==x) //树根的父节点就是自己2.从某个节点开始寻找树根:while(p[x] != x) x=p[x];3。判断两个元素是否在同一个集合中,只需要比较这两个元素的根节点是否一样即可。4.合并集合,将一个集合的树根的父节点指向另一个集合的树根。。5.优化(路径压缩):当从一个原创 2021-01-04 11:17:57 · 196 阅读 · 1 评论