
算法
文章平均质量分 96
本专栏详细介绍双指针,滑动窗口,二分查找,前缀和,位运算,分治,链表,哈希表,BFS,DFS,动态规划,图论,数据结构,贪心,等一系列算法
掘根
感谢吾师,导吾以狭路,示吾以通途
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
快速幂算法
【代码】快速幂算法。原创 2025-03-30 23:49:32 · 360 阅读 · 0 评论 -
set与map的底层数据结构
红⿊树(简称RBT),也是⼀棵⼆叉搜索树。它是在搜索树的基础上,使每个结点上增加⼀个存储位表⽰ 结点的颜⾊,可以是Red或者Black,通过对任意⼀条从根到叶⼦的路径上各个结点着⾊⽅式的限 制,确保没有⼀条路径会⽐其他路径⻓出2倍,因⽽是⼀棵接近平衡的⼆叉搜索树。红⿊树相对于AVL树来说,牺牲了部分平衡性以换取插⼊/删除操作时少量的旋转操作,整体来说性能 要优于AVL树。1. 每个结点要么是红⾊要么是⿊⾊;2.根节点和叶⼦结点(这⾥的叶⼦结点不是常规意义上的叶⼦结点,⽽是空结点,如下图中的NIL)原创 2025-03-27 16:55:11 · 1199 阅读 · 0 评论 -
差分算法题
或者根据具体应用场景进行特殊处理。我们假设a数组是我们的原数组,其有效元素从下标1开始,我们的差分数组d的计算过程如下。原创 2025-03-21 11:44:13 · 631 阅读 · 0 评论 -
最短路问题——多源最短路
当处理到第。原创 2025-03-16 21:10:21 · 1033 阅读 · 0 评论 -
最短路问题——单源最短路
是的,所以我们上面也说了: Bellman-Ford算法是比较暴力的把所有的边都更新(即先后对所有的顶点的相邻顶点进行松弛),而不像Dijkstra算法的贪心那样每次选的都是最短的,也因此它一遍过后可能得不出最短的路径,可能需要进行多次迭代。原创 2025-03-16 13:44:00 · 1014 阅读 · 0 评论 -
拓扑排序算法
用unordered_map就比较万能了,完全像刚才想象出来的邻接表结构,我们这里是一个int的数后面挂了一个int数组,那不就和一个节点挂着一个节点的效果一样的吗。我们可以把给的信息抽象称一张有向图,题目问能否完成所有课程学习意思就是能不能把这个课程排个序,说白了就是能否拓扑排序,能否拓扑排序也就是是否这个图是否是有向无环图 —> 有向图中是否有环?,有向图就是边都是有方向的。直接对图来一次拓扑排序,当拓扑排序过程中发现没有入度为0的点的时候,但是图中还有剩余点的时候,此时这个图中一定会有环形结构。原创 2025-03-10 20:41:45 · 1434 阅读 · 0 评论 -
最小生成树
对一个具有 n 个点的连通图进行遍历,对于遍历后的子图,其包含原图中所有的点且保持图连通,最后的结构一定是一个具有 n-1 条边的树,通常称为生成树。说白了,就是有n个结点,但是只有n-1条边,并且这n个结点是连通的。原创 2025-03-13 12:16:45 · 656 阅读 · 0 评论 -
数组模拟实现链表
两个⾜够⼤的数组,⼀个⽤来存数据,⼀个⽤来存下⼀个结点的位置变量 h ,充当头指针,表⽰头结点的位置变量 id ,为新来的结点分位置注意我们这里是有一个头结点的(即h和id所指的位置)int h;// 头指针int id;// 下⼀个元素分配的位置// 数据域和指针域// 下标0位置作为哨兵位// 其中ne数组全部初始化为0,其中ne[i] = 0就表⽰空指针,后续没有结点// 当然,也可以初始化为- 1作为空指针,看个⼈爱好/*原创 2025-03-10 20:42:41 · 987 阅读 · 0 评论 -
Trie树(字典树)
Trie树,又叫字典树前缀树(Prefix Tree)单词查找树或键树,是一种多叉树结构。如下图:上图是一棵Trie树,表示了关键字集合{“a”, “to”, “tea”, “ted”, “ten”, “i”, “in”, “inn”}。根节点不包含字符,除根节点外的每一个子节点都包含一个字符。从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。每个节点的所有子节点包含的字符互不相同。通常在实现的时候,会在节点结构中设置一个标志,用来标记该结点处是否构成一个单词(关键字)。原创 2025-03-09 10:32:18 · 1617 阅读 · 0 评论 -
并查集算法
并查集是一种树形数据结构,用于处理一些不相交集合的合并及查询问题。通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,这样就可以查询某个元素所在的集合、与这个元素在一个集合中的元素,以及更多。只说这些肯定不行,接下来我将详细介绍。原创 2025-03-07 20:18:32 · 811 阅读 · 0 评论 -
单调栈算法题
单调栈(Monotone Stack):其实就是一种特殊的栈,只不过在栈的「先进后出」规则基础上,要求「从栈底到栈顶的元素是单调递增(或者单调递减)」。其中满足从栈底到栈顶的元素是单调递增的栈,叫做「单调递增栈」。满足从栈底到栈顶的元素是单调递减的栈,叫做「单调递减栈」。注意:这里定义的顺序是从「栈底」到「栈顶」。有的文章里是反过来的。本文全文以「栈底」到「栈顶」的顺序为基准来描述单调栈。原创 2025-03-05 21:20:43 · 1068 阅读 · 0 评论 -
高精度(加,减,乘,除)算法题
之前我们遇到数字的时候,遇到的数的时候我们可以使用int来存储,如果说这个数字达到了,那我们可以使用long long来存储。但是要是数值再比这个都大的时候,比如说当数据的数值达到了,这样子我们用什么去存储啊???当数据的值特别⼤,各种类型都存不下的时候,此时就要⽤⾼精度算法来计算加减乘除:先⽤字符串读⼊这个数,然后⽤数组逆序存储该数 的每⼀位;利⽤数组,模拟加减乘除运算的过程。⾼精度算法本质上还是模拟算法,⽤代码模拟⼩学列竖式计算加减乘除的过程。原创 2025-02-20 18:12:25 · 694 阅读 · 0 评论 -
算法竞赛里面的sort函数
sort在默认的情况下是按照升序排序,如何按照降序排序呢?如果是结构体类型数据进⾏排序呢?怎么办?使⽤⾃定义排序⽅式参数解释:指向要排序范围的第一个元素的迭代器或指针。:指向要排序范围的最后一个元素之后位置的迭代器或指针。:自定义的比较函数或函数对象,用于比较两个元素。sort的第三个参数是⼀个可选的⾃定义⽐较函数(或函数对象),⽤于指定排序的规则。如果不提供这个参数,std::sort默认会使⽤⼩于运算符(<)来⽐较元素,并按照升序排序。这个⽐较函数,接受两个参数,并返回⼀个布尔值。原创 2025-01-18 11:06:40 · 779 阅读 · 0 评论 -
算法竞赛里面的STL——堆和priority_queue
此外,双向链表还能迅速定位到删除操作后新相邻的元素,便于我们判断它们是否为未出列的异性,并据此更新堆中的配对信息。那我为什么不建一个大根堆,只要我保证这个堆的大小是k,这样子堆顶的元素就会一直是第k小的。由于我们使用的是大根堆,所以20是优先级最高的元素。时间复杂度:由于底层是一个堆结构,所以删除优先级最高的元素的时间复杂度为O(log n),其中n是优先级队列中的元素数量。所谓第k大,我们完全可以创建一个小根堆,然后保持堆的大小是k,然后这样子就能保证heap.top()就是第k大的元素了。原创 2025-01-17 20:34:37 · 1140 阅读 · 0 评论 -
贪心算法(一文速通)
贪心算法(Greedy Alogorithm)又叫登山算法,它的根本思想是逐步到达山顶,即逐步获得最优解,是解决最优化问题时的一种简单但是适用范围有限的策略。贪心算法没有固定的框架,算法设计的关键是贪婪策略的选择。贪心策略要无后向性,也就是说某状态以后的过程不会影响以前的状态,至于当前状态有关。贪心算法是对某些求解最优解问题的最简单、最迅速的技术。某些问题的最优解可以通过一系列的最优的选择即贪心选择来达到。但局部最优并不总能获得整体最优解,但通常能获得近似最优解。原创 2025-01-16 11:59:24 · 1475 阅读 · 0 评论 -
动态规划七——背包问题
其实,根本不需要负的下标,我们根据实际情况来看,如果这个任务的利润已经能够达标了(即使减去当前任务的利润后小于0),我们仅需在之前的任务中挑选出来的利润至少为0就可以了。背包问题其实是动态规划的核心,但是由于背包问题的种类繁多,而且背包问题的难度层次不齐,有的题目已经升级到竞赛难度了,所以我们这里只讲01背包问题和完全背包问题。给你一个“背包”,这个“背包”的体积是V,给你一堆“物品”,这些“物品”每一个都有价值w和体积v,让你选择一些放入“背包”,得到最大(最小)价值。顺序无关是组合问题的一个特点。原创 2025-01-12 20:49:57 · 1386 阅读 · 0 评论 -
动态规划六——两个数组的dp问题
来进行分类讨论,以确定状态转移方程。当。原创 2025-01-05 13:36:21 · 1234 阅读 · 0 评论 -
动态规划五——回文串问题
我不知道大家有没有看到上面这个dp[i][j] = dp[i + 1][j - 1],也就是说dp[i+1][j-1]一定要比dp[i][j]先算出来!我不知道大家有没有看到上面这个dp[i][j] = dp[i + 1][j - 1],也就是说dp[i+1][j-1]一定要比dp[i][j]先算出来!则我们需要设置另外一个变量j(注意0<j<=i),我们让j从1开始往右边遍历,如果发现【j,i】是回文串,则我们只需要在【0,i-1】区间的基础上加上一刀即可,我们就让dp[i]=dp[j-1]+1。原创 2024-12-31 11:05:12 · 1207 阅读 · 0 评论 -
动态规划四——子序列系列
目录题目一——300. 最长递增子序列 - 力扣(LeetCode)题目二——376. 摆动序列 - 力扣(LeetCode)题目三—— 673. 最长递增子序列的个数 - 力扣(LeetCode)题目四——646. 最长数对链 - 力扣(LeetCode)题目五——1218. 最长定差子序列 - 力扣(LeetCode)题目六——873. 最长的斐波那契子序列的长度 - 力扣(LeetCode)题目七——1027. 最长等差数列 - 力扣(LeetCode)题目八——446. 等差数列划分 II - 子序原创 2024-12-29 18:05:41 · 1266 阅读 · 0 评论 -
动态规划三——子数组系列
两种情况下的最⼤值,就是我们要的结果。但是,由于数组内有可能全部都是负数,第⼀种情况下的结果是数组内的最⼤值(是个负数),第⼆种情况下的 gmin == sum ,求的得结果就会是 0。虽然它没有任何相邻元素来形成翻转的比较符号,但按照题目的要求,我们需要返回一个答案,所以这里返回 1,表示数组中最长的(也是唯一的)“湍流”子数组的长度。nums[i] < 0 时,此时我们要看 g[i-1] 的值(因为负负得正,如果我们知道以 i-1 为结尾的乘积为负数的最长子数组的长度,加上 1 即可)。原创 2024-12-20 10:22:37 · 1155 阅读 · 0 评论 -
动态规划二——简单多状态dp问题
上⼀个问题是⼀个「单排」的模式,这⼀个问题是⼀个「环形」的模式,也就是⾸尾是相连的。但是我们可以将「环形」问题转化为「两个单排」问题:首先我们将上面那些整合成一个函数int rob1(vector<int>&nums,int left,int right)原创 2024-12-18 14:35:47 · 815 阅读 · 0 评论 -
动态规划一 ——斐波那契数列模型+路径问题
dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i - 1][j + 1])) + matrix[i][j] 这个有越界情况啊。否则,万⼀ 发⽣了溢出,我们的答案就错了。不过注意一下:现在状态转移方程变成了dp[i][j]=max(dp[i-1][j],dp[i][j-1])+frame[i-1][j-1]由于我们要求的是有多少种⽅法,因此状态转移⽅程就呼之欲出了: dp[i][j] =dp[i-1][j] + dp[i][j - 1]。原创 2024-12-15 21:27:42 · 1442 阅读 · 0 评论 -
BFS算法题
正常来说,在我们会了单源BFS的使用后,面对多个起点到一个终点的最短路问题也就是多源BFS,我们最先想到的就是暴力做法,也就是将多个起点分成一份份一个起点到一个终点的单源BFS问题,这样我们每个起点到终点的最短路都求出来再找最小值即可,但这种暴力几乎是一定超时的,最差时间复杂度都达到ON^3。用数组表示所连接的节点。这时我们就发现,如果多个起点一块进行BFS搜索,重复的路程不再经过,这时不仅得出的答案正确,而且时间复杂度大大降低,这也就是多源BFS的核心思路,多个起点同时用单源BFS的方法去找最短路。原创 2024-12-13 22:15:33 · 1181 阅读 · 0 评论 -
floodfill算法(DFS,BFS)
啥是 FloodFill 算法呢,最直接的一个应用就是「颜色填充」,就是 Windows 绘画本中那个小油漆桶的标志,可以把一块被圈起来的区域全部染色。这种算法思想还在许多其他地方有应用。比如说扫雷游戏,有时候你点一个方格,会一下子展开一片区域,这个展开过程,就是 FloodFill 算法实现的。类似的,像消消乐这类游戏,相同方块积累到一定数量,就全部消除,也是 FloodFill 算法的功劳。通过以上的几个例子,你应该对 FloodFill 算法有个概念了,现在我们要抽象问题,提取共同点。原创 2024-12-10 21:19:38 · 872 阅读 · 0 评论 -
回溯算法题(DFS)
深度优先遍历主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底...,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先走完一条路,再换一条路继续走。树是图的一种特例(连通无环的图就是树),接下来我们来看看树用深度优先遍历该怎么遍历。1、我们从根节点 1 开始遍历,它相邻的节点有 2,3,4,先遍历节点 2,再遍历 2 的子节点 5,然后再遍历 5 的子节点 9。原创 2024-12-09 19:12:48 · 1335 阅读 · 0 评论 -
递归3——二叉树里的DFS
理解递归,上面的那些题目可不够,必须来看一下二叉树的DFS。深度优先遍历(DFS,全称为DepthFirstTraversal),是我们树或者图这样的数据结构中常⽤的 ⼀种遍历算法。这个算法会尽可能深的搜索树或者图的分⽀,直到⼀条路径上的所有节点都被遍历 完毕,然后再回溯到上⼀层,继续找⼀条路遍历。在⼆叉树中,常⻅的深度优先遍历为:前序遍历、中序遍历以及后序遍历。因为树的定义本⾝就是递归定义,因此采⽤递归的⽅法去实现树的三种遍历不仅容易理解⽽且代码很 简洁。原创 2024-12-04 22:00:09 · 1009 阅读 · 0 评论 -
递归2——分治(快排+归并)
目录分治 题目一——75. 颜色分类 - 力扣(LeetCode)1.1.三指针解法题目二——912. 排序数组 - 力扣(LeetCode)2.1.数组分三块思想实现快速排序题目三——215. 数组中的第K个最大元素 - 力扣(LeetCode) 3.1.快速选择算法题目四——LCR 159. 库存管理 III - 力扣(LeetCode) 4.1.快速选择算法题目五——912. 排序数组 - 力扣(LeetCode)5.1.归并排序(升序)5.2.归并排序(降序) 题目六——LCR 170. 交易逆序原创 2024-11-26 22:34:08 · 1198 阅读 · 0 评论 -
递归1——递归入门算法题
从这章,我们先讲递归,然后讲搜索,然后再讲回溯算法。原创 2024-12-02 22:17:17 · 811 阅读 · 0 评论 -
字符串,栈的算法题
虽然说,我们这里是简单的介绍字符串的题目一般是怎么做,但是不太会深入介绍更多的字符串的算法。原创 2024-11-30 17:08:03 · 939 阅读 · 0 评论 -
哈希表算法题
我们这里不讲哈希表的原理那些,如果想要学习其他更多的,去其他地方,这里只讲实用的东西哈希表是什么?就是一个存储数据的容器。哈希表有什么用?可以快速查询某个元素,时间复杂度是O(1).什么时候使用哈希表?我们需要频繁的查询一个数据的时候,我们就得想到使用哈希表。判断某个元素只出现一次的时候,我们就得想到使用哈希表。虽然二分查找也很快,但是它的使用条件太苛刻了。怎么使用哈希表?其实我们在就已经使用过哈希表了!感兴趣的可以去看一下。原创 2024-11-29 22:22:58 · 1387 阅读 · 0 评论 -
链表算法题
通过观察,我们可以发现,当slow指针走一步时,fast指针走一步或是走两步都满足slow指针指向的是已经遍历过的结点的中间结点。也就是slow指针走一步,fast指针最多可以走两步。所以,我们可以遍历。原创 2024-11-28 16:27:10 · 755 阅读 · 0 评论 -
模拟 算法
这个数列的每一项都是根据前一项来生成的,而生成的方式是通过对前一项进行“行程长度编码”(Run-Length Encoding, RLE)。如果说要模拟,我们就得创建一个矩阵,行数是numRows,那列数是字符串的长度m。如果这个差值x>=d的话,那么我们的中毒时间是要全加上的,即ret+=d。所以我们做这种题目的时候,就要先在草稿纸上面先推演一遍我们的算法流程。如果这个差值x<d的话,那么我们的中毒时间,就变成了ret+=x;接着我们是要往右上方移动,也就是x-1,y+1,直到x=0的时候。原创 2024-11-24 20:48:59 · 911 阅读 · 0 评论 -
位运算算法
于是我们可以像下面这样,一个比特位代表一个字母,这样子我们只要26个比特位就能表示出所有的小写字母,我们让0代表该字母没出现过,1代表该字符出现过。然后,当我们对这个取反后的数加1时,会从最低位(最右侧)开始,遇到第一个0时停止进位,并将这个0及其之后的所有位都设置为1,而之前的所有位都保持不变(但由于是取反后的数,所以它们实际上是原数中对应位置的相反值)。假设我们有一个数 n = 29,并且我们想知道它的二进制表示中的第 x = 3 位(从右向左,从0开始编号)是0还是1。位(从0开始计数)修改成1。原创 2024-11-23 11:18:48 · 1246 阅读 · 0 评论 -
前缀和算法
前缀和其实我们很早之前就了解过的,我们求数列的和时,Sn = a1+a2+a3+...an;此时Sn就是数列的前 n 项和。例 S5 = a1 + a2 + a3 + a4 + a5;所以我们完全可以通过 S5-S2 得到 a3+a4+a5 的值,这个过程就和我们做题用到的前缀和思想类似。首先,先记忆下面这两点前缀和是需要借助一个数组的。所以我们需要创建一个数组presum我们的前缀和数组presum[n]里保存的就是原数组nums前 n 项的和。见下图我们通过前缀和数组保存前 n 位的和,原创 2024-11-20 18:34:27 · 1362 阅读 · 0 评论 -
二分答案算法
如果「解空间」在从大到小的变化过程中,「判断」答案的结果出现「二段性」,此时我们就可以「二分」这个「解空间」,通过「判断」,找出最优解。因此,在解空间中,根据 ret 的位置,可以将解集分成两部分,具有「二段性」。在解空间中,根据 ret 的位置,可以将解集分成两部分,具有「二段性」,那么我们就可以「二分答案」。在解空间中,根据 ret 的位置,可以将解集分成两部分,具有「二段性」,那么我们就可以「二分答案」。的位置,可以将解集分成两部分,具有「二段性」,那么我们就可以「二分答案」。原创 2025-03-29 21:05:35 · 823 阅读 · 0 评论 -
二分查找算法
我们如果在循环里面判断,就会需要求middle,这个时候middle就不变化,而nums[middle]是符合nums[middle]>=target的,所以会执行right=middle;左边不一定有峰值,右边一定有峰值,这个时候我们应该让mid往右边去靠近,那只能移动left,这个时候nums[mid]绝对不是是右边的峰值,而nums[mid+1]有可能是右边(不包括i)的峰值,所以我们让left=mid+1即可。当我们的数据量很大的时候,这个right+left的时候,是会溢出的。原创 2024-11-16 20:56:51 · 905 阅读 · 0 评论 -
滑动窗口算法
算法思路由于此问题分析的对象是「一段连续的区间」,因此可以考虑「滑动窗口」的思想来解决这道题。从i位置开始,窗口内所有元素的和小于target(当窗口内元素之和第一次大于等于目标值的时候,就是i位置开始,满足条件的最小长度)。将右端元素划入窗口中,统计此时窗口内元素的和。如果窗口内元素之和大于等于target:更新结果,并将左端元素划出去的同时继续判断是否满足条件并更新结果(因为左端元素可能很小,划出去之后依旧满足条件)。right++,让下一个元素进入窗口。相信科学。原创 2024-11-12 19:55:52 · 1370 阅读 · 0 评论 -
双指针——快慢指针+对撞指针
iii. 当 nums[left] + nums[right] > target 时,同理我们可以舍去 nums[right] (最⼩的数都满⾜不了你,你也没救了)。让 组数据,⽽ right-- ,继续⽐较下⼀组,而 left 指针不变(因为他还是可以去匹配⽐ nums[right] 更⼩的数的)。根据「解法⼀」中的优化思想,我们可以固定⼀个「最⻓边」,然后在⽐这条边⼩的有序数组中找 出⼀个⼆元组,使这个⼆元组之和⼤于这个最⻓边。但是这个需要判断三次,如果我们知道三者的大小关系,我们只需判断一次即可。原创 2024-05-14 18:47:31 · 1482 阅读 · 2 评论 -
C++算法竞赛必刷127道OJ题
。原创 2024-12-01 22:05:21 · 1252 阅读 · 0 评论