![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
算法基础
文章平均质量分 70
Zenita
这个作者很懒,什么都没留下…
展开
-
Section 16.DFS与BFS
一、DFS与BFS的原理有请我们的五毛钱特效!DFS|BFS二、DFS的实现AcWing842https://www.acwing.com/problem/content/844/#include <iostream>using namespace std;const int N = 10;int n;int path[N]; //存储路径,DFS只存储当前路径bool st[N]; //用来存储当前这个数有没有被用过void dfs(int u) /原创 2022-02-17 22:10:51 · 380 阅读 · 0 评论 -
Section 15.Hash表
一、什么是哈希表? 通过一个散列函数,将任意元素映射在数组下标中。它提供了快速的插入操作和查找操作,无论哈希表中有多少条数据,插入和查找的时间复杂度都是为O(1)原创 2022-02-12 22:16:28 · 546 阅读 · 0 评论 -
Section 14.堆
一、堆是什么?堆是一棵完全二叉树完全二叉树:除了最后一层节点,全部非空的二叉树,且最后一层节点从左往右排布小根堆:每个节点都小于两个子节点存储方式:一维数组,下标从1开始,下标x的左子节点是下标2x,右子节点是下标2x+1二、如何手写一个堆?初始化,读入堆for (int i = 1; i <= n; i++) //n是堆的大小 scanf("%d", &h[i]);::size = n;for (int i = n...原创 2022-02-11 17:08:01 · 455 阅读 · 0 评论 -
Section 13.并查集
一、并查集的作用将两个集合合并 询问两个元素是否在同一个集合当中二、并查集的基本原理每个集合用一棵树来表示。树根的编号就是整个集合的编号。每个节点存储它的父节点,p[x]表示x的父节点如何判断树根:if(p[x]==x) 如何求x的集合编号:while(p[x]!=x) x=p[x]; 如何合并两个集合:px是x的集合编号,py是y的集合编号,p[x]=y三、实现#include <iostream>using namespace std;cons...原创 2022-02-10 22:10:17 · 267 阅读 · 0 评论 -
Section 12.Trie树
一、Trie树的基本作用:高效地存储和查找字符串集合的数据结构 例如,我们要存储以下字符串:abcdef,abdef,aced,bcdf,bcff,cdaa,abc,我们可以以树的形式存储:在这里,我们以标红的形式来标记每个字符串的末尾。二、代码实现初始化#include <iostream>using namespace std;const int N = 100010;char str[N];int son[N][26]; //所有节点...原创 2022-02-10 17:50:32 · 302 阅读 · 0 评论 -
Section 11.Knuth-Morris-Pratt
一、暴力求解!string s, p; //长度为n的模式串s和长度为m的模版串pfor (int i = 1; i <= n; i++){ bool flag = true; for (int j = 1; j <= m; j++) { if (s[i - j + 1] != p[j]) { flag = false; break; } }}Time LimitError警告!二、优雅地求解...原创 2022-01-23 16:01:03 · 129 阅读 · 0 评论 -
Section 10.栈和队列
一、基本概念栈:先进后出。越后插入的元素,越先弹出来(有底的圆桶) 队列:先进先出。越先插入的元素,越先弹出来(无底的圆桶)二、实现栈:#include <iostream>using namespace std;const int N = 100010;int stk[N], tt = 0;//初始化栈,tt是当前的下标//插入xstk[++tt] = x;//弹出tt--;//判断栈是否为空if (tt > 0)//非空else //空//原创 2022-01-14 17:54:18 · 133 阅读 · 0 评论 -
Section 9.链表
一、用数组模拟单链表邻接表:单链表的集合单链表#include <iostream>using namespace std;const int N = 100010;//head表示头节点的下标//e[i]表示节点i的值//ne[i]表示节点i的next指针是多少//idx表示当前已经用到了哪个节点int head, e[N], ne[N], idx;void init() //初始化{ head = -1; //链表是空的 idx = 0; //从.原创 2022-01-13 16:20:01 · 198 阅读 · 0 评论 -
Section 8.离散化(整数有序)
一、离散化的含义:对于数组a[]={1,3,100,2000,500000,......},把他们一一映射到下标0,1,2,3,4,......的过程叫做离散化注意:a[]中可能有重复元素 ,需要去重 如何算出x离散化后的值:二分二、离散化的过程vector::erase()的用法:从vector中删除一个元素,参数为要删除元素的位置vector::erase(first,last)的用法:从vector中删除范围在[first,last)中的元素(不包含last)v.原创 2022-01-12 17:31:43 · 407 阅读 · 7 评论 -
Section 7.位运算
一、基础知识&:与:两个位都为1时,结果才为13&5 即 0000 0011 & 0000 0101 = 0000 0001,因此 3&5 的值得1|:或:两个位都为0时,结果才为03|5即 0000 0011 | 0000 0101 = 0000 0111,因此3|5的值得7^:异或:两个位相同时为0,相异时为13^5即 0000 0011 ^ 0000 0101 = 0000 0110,因此3^5的值得6//交换两个数void Swa原创 2022-01-12 15:40:39 · 176 阅读 · 0 评论 -
Section 6.双指针
核心思想:对于一个序列:用两个指针维护一段区间 对于两个序列:用两个指针对两个序列进行有规律地维护(如归并排序)将时间复杂度O(n^2)的算法优化至O(n)for (int i = 0; i < n; i++){ for (int j = 0; i < m; j++) { //... }}将朴素变得高雅(for (int i = 0, j = 0; i < n; i++){ while (check(i, j)) j++; //...}原创 2022-01-11 21:58:55 · 249 阅读 · 0 评论 -
Section 5.前缀和与差分
前缀和与差分互为逆运算一、一维前缀和设有序列,则该序列的前缀和 作用:快速求出到之间所有数的和:二、二维前缀和设有矩阵,则该矩阵前缀和 前缀和的数学意义:与所形成的矩形内部所有数的和,按照这个思路公式就很容易推啦 作用:求出与所形成的矩形内部所有数的和:注意:前缀和的均为0,因为需要考虑边界情况三、一维差分设有序列,构造,使得 方法:使 tips:其实不需要考虑构造,因为差分数列就相当于在原数列全是0的基础上,在这个点加上对应数{ for...原创 2022-01-11 18:38:17 · 277 阅读 · 0 评论 -
Section 4.高精度
一、高精度加法(正数+正数)大整数的存储:将个位存在a[0],十位存在a[1],百位存在a[2]......,方便进位,因为如果按照正序存储的话,最高位需要进位时,所有数字都需要向右移一位 模拟竖式加法.size()函数的用法:假设有vector<>a,则a.size()返回数组a的长度.push_back()函数的用法:函数将一个新的元素加到vector<>的最后面,位置为当前最后一个元素的下一个元素,参数为要插入的值#include <iost原创 2022-01-10 22:17:24 · 234 阅读 · 0 评论 -
Section 3.二分法
一、二分的本质在一个序列中,存在某种性质,使得该序列可以一分为二,使左半边满足这种性质,右半边不满足这种性质,二分可以寻找这种性质的边界 常用于边界问题二、整数二分的过程当我们想二分找出x点时找到一个中间值mid=(l+r+1)/2,判断这个点的性质是否具有左半边性质(l+r+1的原因是下面的更新方式是l=mid) 如果具有,则真正的边界可能在[mid,r]中(之后的更新方式:l=mid),否则真正的边界可能在[l,mid-1]中(之后的更新方式:r=mid-1)int dich原创 2022-01-10 15:50:57 · 362 阅读 · 0 评论 -
Section 2.归并排序
一、中心思想:分治以中间点为界:mid=(l+r)/2 递归排序分界点左边和右边 归并——合二为一二、核心内容:合二为一分界点左边从小到大排序:数组a,分界点右边从小到大排序:数组b,答案数组ans 指针i,j分别指向a、b的第一个数,如果i指向的数比j指向的数小,则将i指向的数移至ans,指针i向后移动,j指向的数比i指向的数小时同理。若i先到达末尾,则j及以后的数全部移至ans,若j先达到末尾同理三、上代码!void merge_sort(int q[], int l, int原创 2022-01-09 22:59:46 · 383 阅读 · 0 评论 -
Section 1.快速排序
一、中心思想:分治确定分界点x:q[l],q[r],q[(l+r)\2],或者任取一点 调整区间,小于等于x的放在x左边,大于x的放在x右边 递归将左边和右边分别排好序二、核心内容:调整区间暴力做法:另建两个数组a[],b[] 对q[l]到q[r]扫描,小于等于x的丢到a,大于x的丢到b 先将a存进q,再接着存b虽然很不优雅,但是咱不差这内存,时间复杂度是一样的0.0优雅的做法:在l处和r处设置一个“指针”i,j 如果i处小于等于x,则i右移,直到i处大于x停下;然后判断.原创 2022-01-09 19:28:39 · 166 阅读 · 0 评论 -
Section 0.递归的本质
一、解释 如果递归函数调用自己,则被调用的函数也将调用自己,这将无限循环下去,除非代码中包含终止调用链的内容。通常的方法是将递归调用放在if语句中。例如,void类型的递归函数x()的代码如下:/*void x(参数){ 代码块1 if (递归条件) x(参数) 代码块2}*/ 递归条件最终将为false,调用链将断开。 只要if语句为true,每个x()调用都将执行代码块...原创 2022-01-09 20:28:49 · 465 阅读 · 0 评论