
算法基础课
文章平均质量分 55
C语言——数据结构
孙同学要努力
这个作者很懒,什么都没留下…
展开
-
基础算法--背包问题(01背包问题、完全背包问题、多重背包问题、分组背包问题)
背包问题:给我们 i 件物品,每件物品都有体积 vi 和权重 wi ,给我们限制条件,让我们选择在背包的容量内,物品达到权重最大。原创 2023-01-22 16:15:55 · 1939 阅读 · 0 评论 -
基础算法——二分图 -- 染色法判别二分图、最大匹配数(匈牙利算法)
x3发现y1已经被匹配了,而y2也被匹配完了,所以x3会让x1能不能换个匹配对象,结果x1就找到了y2,但是y2已经被x2给占了,就让x2能不能换个,x2就找到了y3,这时候x1匹配y2,x2匹配y3,x3从而就成功匹配了y1,最后x4匹配了y4,因此图中最大匹配数就是4(图中的图连线包括虚线和实线)设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。原创 2022-11-10 14:00:06 · 372 阅读 · 0 评论 -
基础图论算法--最小生成树——prim、Kruskal算法
Prim算法更使适应稠密图,时间复杂度为:O(n^2),和Dijkstra算法很相似也肯可以用堆优化来解决稀疏图;但是对于稀疏图,我们更喜欢使用Kruskal(克鲁斯卡尔)算法,时间复杂度为:O(mlogm)Kruskal算法需要判断两个点是否在集合中,以及如何把这两个点连城的一条边加入到集合中,这就需要我们使用。Kruskal算法存边的方法任意,就用最简单的结构体存边即可。特点一:若砍去他的一条边,则会使生成树变成非连通图。,使这条边的两头连通,知道所有的节点都连通。中所有的顶点,并且只含尽可能少的边。原创 2022-11-08 21:04:53 · 930 阅读 · 1 评论 -
最短路——Dijkstra(朴素法、堆优化)、Bellman-Ford、SPFA(求负环)、Floyd算法
处理负权边我们是采取Bellman-Ford算法或者是SPFA,SPFA算法的适用处更广,但是当有边数权限(在多少步下完成)的时候,我们只能适用Bellman-Ford算法,但在其他情况下我们都可以使用SPFA算法;我们上面知道Bellman_Ford算法会遍历每条边,但是有些边遍历是没有意义的,我们只需要遍历那些到源点距离变小的点才能找到最短路径;SPFA中松弛的概念:一个点到另一个点的路径选择有很多,我们要想找到最优路径,我们肯定要找到中间那个点距离源点距离变小的点,那样这两点之间的路径才会变小。原创 2022-10-31 20:05:41 · 579 阅读 · 1 评论 -
一篇文章搞懂约数——试除法求约数、约数个数、约数之和
算数基本定理:N = p1^a1 * p2^a2 * … * pk^ak约数个数:ans = (a1 + 1)(a2 + 1)(a3 + 1)…(ak + 1)约数之和:ans = (p1^0 + p1^1 + … + p1^k) * … * (pk^0 + pk^1 + … + pk^k)原创 2022-10-19 17:34:25 · 1139 阅读 · 3 评论 -
一篇文章搞懂质数——试除法判别质数、分解质因数、筛质数(埃氏筛法、线性筛法)
例如:1,3,5,7,11,13,17,19等都是素数,他们只能被自己本身和1整除。即数字n,如果在2 ~ n-1之间都不能被n整数,那么n就是质数。**技巧:**在写循环的时候,我们不需要写 i原创 2022-10-17 21:37:52 · 1649 阅读 · 0 评论 -
数与图的深度优先搜索、宽度优先搜索、拓扑序列(邻接矩阵、邻接表)
数据结构中,对于图的存储我们是使用邻接矩阵或者邻接表来进行存储的。树就是一种特殊的图,而图我们又分为有向图和无向图,而无向图又是一种特殊的有向图,即每两点之间都存在两条通路。邻接矩阵存储,是指用一个一维数组存储图中顶点的信息,用一个二维数组存储图中边的信息,即各顶点之间的邻接关系,存储顶点之间邻接关系的二维数组称为邻接矩阵。用的很少,我们重点要掌握邻接表。原创 2022-10-15 15:57:12 · 746 阅读 · 0 评论 -
深度优先搜索(DFS)、广度优先搜索(BFS)
反对角线 y=x+by=x+b, 截距 b=y−xb=y−x,因为我们要把 bb 当做数组下标来用,显然 bb 不能是负的,所以我们加上 +n+n (实际上+n+4,+2n都行),来保证是结果是正的,即 y - x + n。核心目的:找一些合法的下标来表示dgdg或udgudg是否被标记过,所以如果你愿意,你取 udg[n+n−u+i]udg[n+n−u+i] 也可以,只要所有(u,i)(u,i)对可以映射过去就行。对于广度优先遍历,我们都是存储每个点到原点的距离,这样,就可以找到最优解了。原创 2022-10-14 15:07:56 · 123 阅读 · 0 评论 -
区间合并。
可以先按左端点排序,再维护一个区间,与后面一个个区间进行三种情况的比较,存储到数组里去。原创 2022-09-27 16:18:47 · 84 阅读 · 0 评论 -
离散化——区间和
离散化的本质就是映射,但是我们为什么需要映射来做呢?有时候,给我们的数据值域很大(10^9),但是数字个数却不是很大(10 ^5),但是这些数据并不是连续的,中间有很多空的地方(0),如果把这些0加上,我们想要开辟一个数组是根本无法达到的。(好像静态全局数组最大能开10 ^7),这时候我们就需要利用离散化,把这些有用的数据映射到一个新的数组上。原创 2022-09-26 17:53:11 · 157 阅读 · 0 评论 -
哈希表——拉链法、开放寻址法、字符串前缀和哈希
哈希表又称散列表哈希表的内容,我们需要掌握两个内容:1.哈希表的存储结构;包括①拉链法②开放寻址法2.字符串的哈希方式拉链法:开放寻址法:例题:模拟散列表。原创 2022-09-23 19:14:00 · 315 阅读 · 0 评论 -
堆——堆排序、模拟堆
堆的存储使用一个一维数组来存储的,数组的下标我们是从1开始的,根节点下标为x的左孩子的下标为2x,右孩子的下标为2x+1.堆分为小根堆和大根堆,小根堆的父节点都要比子节点的值小,大根堆相反。2.求集合当中的最小值。4.删除任意一个元素。5.修改任意一个元素。原创 2022-09-22 14:53:29 · 267 阅读 · 0 评论 -
并查集(路径压缩)
基本原理:每个集合用一棵树来表示,树根的编号就是整个集合的编号,每个节点存储他的父节点,p[x]表示x的父节点。在刚开始的时候,每个集合都是一个独立的集合,都只有一个数,并且集合都是等于自己本身下标的数;所以 p[6] = p[3],也就可以 p[find(6)] = find(3)因为6的祖宗节点本来就是6,此时以5为祖宗节点的集合就为{5,3,6}问题3:如何合并两个集合编号,py是y的集合编号,p[x] = y。所以3的祖宗节点就变成了5,此时以5为祖宗节点的集合为{5,3}例如:p[1] = 1;原创 2022-09-12 16:42:09 · 1062 阅读 · 0 评论 -
Trie树——Trie字符串统计
Tire:高效的存储和查找字符串集合的数据结构。原创 2022-09-11 14:08:35 · 325 阅读 · 0 评论 -
KMP字符串
KMP算法是解决字符串的匹配问题。原创 2022-09-09 14:41:49 · 102 阅读 · 0 评论 -
单调栈和单调队列(滑动窗口)
单调递增栈:在保持栈内元素单调递增的前提下(如果栈顶元素大于要入栈的元素,将其弹出),将新元素入栈。单调递减栈:在保持栈内元素单调递减的前提下(如果栈顶元素小于要入栈的元素,将其弹出),将新元素入栈。给定一个序列,求序列中的每一个数左边或右边第一个比他大或比他小的数在什么地方;什么时候使用单调栈呢?原创 2022-09-08 15:23:20 · 94 阅读 · 0 评论 -
数组模拟栈和队列
【代码】数组模拟栈和队列。原创 2022-09-07 14:38:51 · 90 阅读 · 0 评论 -
数组模拟实现单链表、双链表
我们之前以前学习了链表的知识,当时我们是使用结构体+指针的方式对链表进行增删改查等操作。我们要知道当初我们在实现链表的时候,是不断用动态内存来申请节点的,当我们的链表数据非常大时,那么采用动态内存申请空间会非常频繁,结构就是速度太慢。其实,用数组模拟实现链式是静态链表。在面试过程中,经常会考结构体+指针的问题,而笔试时,更多的是用数组实现链表,因为数据会很大。注意我们这里面的idx是一直往下加,就算某个元素被删除,他的下标还是在的,只是在我们链表里面被删除了,所以用数组模拟实现链表是会造成空间浪费的。原创 2022-09-05 16:45:35 · 351 阅读 · 0 评论 -
前缀和与查分(一维前缀和,二维前缀和(子矩阵的和)一维差分、二维差分(差分矩阵))
百度给的定义就是:前缀和表示一个序列的前n项和,理解为数组的话就是从下标为1到n(定义成数组时就从下标为1开始接收该序列),而差分就是前缀和的逆运算,前缀和与差分数组是对应关系。前缀和就是指某个序列的前n项和,类似于数列的求n项和。我们前缀和一般都是从a1开始,默认初始值a0的值为0;那么前缀和的公式就是:s(i) = a(1) + a(2) + ……+ a(i);原数组: a[1], a[2], a[3], a[4], a[5], …, a[n]前缀和 Si为数组的前 i项和。原创 2022-09-02 11:35:45 · 810 阅读 · 0 评论 -
高精度算法(加减乘除)
在实现高精度加法的时候,我们要注意,容器(也就是数组)的低位要存放数据的个位。比如说一个大数字是1234567,那么,放到vector容器的第一个数字(也就是v[0])放个位7;因为我们知道两个数字相加,肯定会产生进位,如果我们是把数据的高位放到容器中的前面,如果高位需要进位,那么需要每位都要往后面移动一位,效率会非常低。高精度减法和高精度加法一样,也是那样存储大数字的。我们在实现A - B的时候默认是A大于B的,且A、B都是正数,如果A小于B的话,我们就实现B - A,前面加个符号就可以了。...原创 2022-08-28 17:46:21 · 325 阅读 · 0 评论 -
位运算——二进制中1的数
我们知道循环先进去,n>>3,就是把10右移三位,是1,1再与1按位与,得1;然后n>>2,把10右移两位,是10,10再与1(01)按位与,得1;然后n>>1,把10右移一位,得101,101与1(001)按位与的001,得1;位运算我们主要学了六种按位与(&),按位或(|),按位异或(^),按位取反(~),左移()。我们再来看一个公式求返回数字n在二进制中的最后一位1,lowbit(n)=n&-n;这样,我们就可以计算出数字n在二进制中的最后一位1;...原创 2022-07-29 17:56:19 · 762 阅读 · 0 评论 -
双指针算法
双指针算法在解决某些算法中是常用的工具,双指针算法非常灵活,可以降低时间复杂度。一般不用双指针算法时,我们要写两个for循环嵌套,而利用了双指针,时间复杂度就从n的平方,变成了n。给定一个长度为n的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。第二行包含n个整数(均在0∼100000范围内),表示整数序列。我们在键盘上输入几个单词,用空格来断开,然后要求我们输出一行一个单词。共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。一个非常简单的例子,利用双指针来解决。......原创 2022-07-28 16:58:04 · 107 阅读 · 0 评论 -
“二分”的深入理解
这里,我们就要想一下为什么算mid的时候要先加上1呢,假设我们现在没有加上1,当我们只有两个数22的时候,此时l=0,r=1,mid=0,此时q[mid]>1的时候,此时l=0,r=1,mid=1,q[mid]原创 2022-07-27 15:55:45 · 120 阅读 · 0 评论 -
深入了解《归并排序》
归并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法(DivideandConquer)的一个非常典型的应用,且各层分治递归可以同时进行。归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。归并排序自我感觉较为复杂,特别是在递归的时候,很绕一般分为三个步骤。...原创 2022-07-19 11:48:44 · 103 阅读 · 0 评论 -
深入理解《快速排序》
第二步调整区间,让小于等于3的都在左边,让大于等于3的都在右边,如下。第一步随便选择一个数字,我们就选择第一个数3。快速排序是排序中效率较高的一种排序方法。例如给五个数字,让其排序。...原创 2022-07-18 17:53:07 · 121 阅读 · 0 评论