
算法导论笔记
文章平均质量分 55
以《算法导论》、《剑指offer》、leetcode习题为基础,总结解题规律。
持续学习,不断沉淀
C++开发工程师
展开
-
编程题输入数据处理:读取多行string,空行退出;并根据“, ”拆分成int
1、读取多行int输入形成[5,3]的矩阵:int a{0};int b{0};int c{0};vector<vector<int>> input;vector<int> tmp;for(int i = 0;i<5;i++){ cin>>a>>b>>c; tmp.push_back(a); tmp.push_back(b); tmp.push_back(c); input.push_back(tmp);原创 2020-11-08 00:35:10 · 163 阅读 · 0 评论 -
链表问题技巧:使用伪头节点
小技巧:对于链表问题,返回结果为头结点时,通常需要先初始化一个预先指针 pre,该指针的下一个节点指向真正的头结点head。使用预先指针的目的在于链表初始化时无可用节点值。struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {}};ListNode* pre = new ListNode(0); //0为预先指针的值,pre->next指向headListNod原创 2020-06-12 17:32:47 · 1364 阅读 · 2 评论 -
双指针问题(3):滑动窗口算法
1、滑动窗口介绍:滑动: 说明这个窗口是移动的,也就是移动是按照一定方向移动的。窗口: 窗口大小并不是固定的,可以不断扩容或缩小,直到满足一定的条件;当然也可以是固定大小。滑动窗口算法的大体流程: 以字符串为例(数组同理)初始化窗口大小: 利用双指针技巧,初始化窗口左右值 left=right=0,[left, right)称为窗口。右移right指针扩大窗口: 逐步扩大窗口,直到窗口中字符串满足一定条件(包含特定字符)。右移left指针缩小窗口: 逐步缩小窗口,直到窗口中字符串不再满足条件(原创 2021-04-21 21:39:43 · 268 阅读 · 0 评论 -
双指针在解题中的应用:同向双指针;相向双指针
1、同向双指针:2、相向双指针:原创 2020-06-18 14:53:52 · 768 阅读 · 0 评论 -
二分法的使用技巧、注意点
1、分段有序查找目标值:「分段数组查找目标值」问题,都可以通过将数组分段,从而转化成我们熟悉的「有序数组查找目标值」问题!思路来源:力扣题:1095. 山脉数组中查找目标值。根据峰顶将山脉数组分为「升序数组」和「降序数组」两段,分别进行二分查找。2、中点mid更新方式:int mid = (left + right) / 2;这种写法在绝大多数情况下没问题,但是在 left 和 right 特别大的场景中,left + right 会发生整形溢出,得到一个负数,mid 的值随之也是负数。改进的原创 2020-06-16 13:53:33 · 1278 阅读 · 0 评论 -
递归遍历与for循环遍历:递归遍历实现、理解简单
1、想法来源:力扣题14- I. 剪绳子给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0] x k[1] x ... x k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。示例 1:输入: 2输出: 1解释: 2 = 1 + 1, 1 × 1 = 1示例 2:输入: 10输出: 36原创 2020-06-08 13:34:52 · 3125 阅读 · 0 评论 -
所有节点对最短路径的Floyd算法:可以有负权边,但不能有负权回路
Floyd-Warshall算法,中文亦称弗洛伊德算法,是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题。1、形象的理解:(此部分内容为转载整理)原文见:彻底弄懂最短路径问题博客第2.2部分。1.1、Floyd算法的基本思想:从任意节点A到任意节点B的最短路径不外乎2种可能:1是直接从A到B;2是从A经过若干个节点到B。所以,我们假设dist(AB)为节点A到节点B的最短路径的距离,对于每一个节点K,我们检查dist(AK) + dist(转载 2020-06-05 16:44:33 · 9417 阅读 · 0 评论 -
单源最短路径Dijkstra算法:只能处理正权边,可以有环
1、算法介绍:迪杰斯特拉(Dijkstra)又叫狄克斯特拉算法,用于求所有权重边都非负情况下的单源最短路径问题,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。2、伪代码描述:1、初始化:设d[0]=0,其他d[i]=INF;//INF是一个很大的值,用来替代正无穷2、循环V次(循环节点集个数次,也可以像图中表示,队列q会pop()V次) { 在所有未标号结点中,选出d值最小的结点x;(第一次为源点,d为0) 给结点x标记;原创 2020-06-03 16:05:33 · 5768 阅读 · 0 评论 -
有向无环图DAG的拓扑排序与单源最短路径求解:可以有负权边,但不能有回路(即使正权环)
1、有向无环图的拓扑排序:用深度优先搜索后 节点结束时间逆序排序 得到的序列为拓扑序列,例:1.1、伪代码描述:可以在O(V+E)时间内完成拓扑排序,因为DFS运行时间为O(V+E)。2、有向无环图的单源最短路径:2.1、图中节点初始化伪代码:void initializeSingleSource(Graph* G, node& s){ for(each node in 顶点集合V){ node.d = 无穷大; // 初始化距离无穷大 node.pre = NULL;原创 2020-06-03 11:04:38 · 586 阅读 · 0 评论 -
单源最短路径Bellman-Ford算法:可处理负权边、负权回路情况
1、贝尔曼-福特(Bellman-Ford)相比迪科斯彻(Dijkstra)算法:优缺点Bellman-FordDijkstra处理问题情况可处理负权边、负权回路只能处理正权边时间复杂度高,O(V*E)低,O(V^2)实现代码实现简单代码实现复杂2、Bellman-Ford算法介绍:Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。2.1、算法步骤:初始化:将源点距离设为0(d[s]—>0),其余所有顶点的原创 2020-06-02 19:58:50 · 2043 阅读 · 0 评论 -
力扣题解34:二叉树中和为某一值的路径。方法:回溯法(循环+递归),在DFS上的修改(路径记录)
1、题目描述:链接输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。示例:给定如下二叉树,以及目标和 sum = 22, 5 / \ 4 8 / / \ 11 13 4 / \ / \ 7 2 5 1返回:[[5,4,11,2],[5,8,4,5]]2、思路:二叉树路径搜索问题,首原创 2020-05-31 16:23:28 · 315 阅读 · 0 评论 -
力扣题解:542题01矩阵 知识点:多源BFS(确定当前遍历层次与否两类模板)用于求最短距离
1、题目描述:题目链接给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。两个相邻元素间的距离为 1 。示例 1:输入:0 0 00 1 00 0 0输出:0 0 00 1 00 0 0注意:给定矩阵的元素个数不超过 10000。给定矩阵中至少有一个元素是 0。矩阵中的元素只在四个方向上相邻: 上、下、左、右。2、思路:搞懂题目考察什么,剩下的任务就是套模板!a) 首先看到在矩阵上搜索距离,思考关于图的解法。b) 本题给出了一个场景:求每个1到0的最短距原创 2020-05-31 11:17:07 · 517 阅读 · 0 评论 -
【编程题】丑数Ⅲ:涉及二分查找、最大公约数、最小公倍数算法
1、题目:请你帮忙设计一个程序,用来找出第 n 个丑数。丑数是可以被 a 或 b 或 c 整除的 正整数。示例 :输入:n = 3, a = 2, b = 3, c = 5输出:4解释:丑数序列为 2, 3, 4, 5, 6, 8, 9, 10... 其中第 3 个是 4。提示:1 <= n, a, b, c <= 10^92、思路:首先,为什么第一时间能想到二分法?让我们观察题目,可以看到,最终状态(即n)的范围非常大。试图自底向上递推或是按照通常的自顶向下回溯显然会超时(原创 2020-05-13 14:13:10 · 276 阅读 · 0 评论 -
贪心算法构造最小生成树:kruskal算法、prim算法
1、定义:在连通无向图G(V,E) 中找到一个边E的无环子集T,使其能够将所有节点连接起来,又具有最小权重。a)由于T是无环的,可看作是一棵树;b)由于是图G生成的,所以称为(图G的)生成树;c)由于T具有权重最小,所以称为最小生成树。由于T是无环的,所以V个顶点一定有V-1条边。2、贪心策略:每次生长最小生成树的一条边,进行V-1次循环完成建树。生长的边必须轻量级边(权重最小)且不构成环。...原创 2020-05-10 17:34:10 · 1355 阅读 · 0 评论 -
求解有向图的强连通分量:Kosaraju算法
1、强连通分量介绍:在有向图G中,如果两个顶点vi,vj间有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。求解强连通分量的方法如下:2、Kosaraju算法:算法基于的事实: 逆图G^T(同图中的每边的方向相反)和原图G有着完全相同的连通分支.也就是说,如果顶点s和t在原创 2020-05-09 17:05:07 · 1688 阅读 · 0 评论 -
贪心算法(求解最优化问题)及其应用赫夫曼编码
1、贪心算法求解流程:通常自顶向下设计:做出一个选择(做局部最优选择),然后求解剩下的那个与原问题类似的子问题。2、贪心算法设计步骤:3、0-1背包问题与分数背包问题:0-1背包问题:【动态规划】01背包问题(通俗易懂,超基础讲解)分数背包问题:贪心算法,见算法导论16.2节4、赫夫曼编码: 目标:字符出现频率高,使其二进制位数少对于字符等数据,根据其出现频率,通过赫夫曼贪心算法构造出字符的最优前缀码(二进制表示),从而降低所占空间。前缀码:没有任何码字是其他码字的前缀。最优前缀码对应原创 2020-05-09 11:16:25 · 999 阅读 · 0 评论 -
邻接链表、矩阵表示图时的广度优先搜索与深度优先搜索
1、图的基本表示:G(V,E)表示图,V为vector节点,E为edge边。邻接链表常用于表示稀疏图,邻接矩阵常表示稠密图,其中图规模较小时也常用邻接矩阵表示,因为矩阵表示简单。无向图邻接链表长度之和为2|E|,有向图邻接链表长度之和为|E|。2、广度优先搜索BFS:算法在发现所有距离源节点s为k的所有节点后,才会发现距离源节点s为k+1的其他节点。2.1、邻接矩阵表示的广度优先...原创 2020-05-08 13:28:35 · 891 阅读 · 0 评论 -
动态规划问题实例(3):最长公共子序列/字串;最长回文子序列/子串
1、问题描述:给定两个序列,求两序列的最长公共子序列,例子:原创 2020-05-07 10:06:49 · 348 阅读 · 0 评论 -
动态规划问题实例(2):矩阵链乘法
1、动态规划原理:适合应用动态规划求解的最优化问题应具备的两个要素:最优子结构和子问题重叠。1.1、最优子结构: 如果一个问题的最优解包含其子问题的最优解,则该问题具有最优子结构。例子,长度为n的钢条的最优切割方案由第一次切割后两段钢条的最优切割方案组成;矩阵链问题同理。对于不同问题领域,最优子结构的不同体现在两个方面:原问题的最优解中涉及多少个子问题。例,钢条切割包含一个子问题;矩阵链...原创 2020-05-05 15:30:32 · 617 阅读 · 0 评论 -
动态规划解题思路、与分治法的区别;问题实例(1):钢条切割
1、动态规划与分治法的区别:都利用递归,但分治法的子问题不重复,动规的子问题重复,因此需要表格保存子问题的解,以避免重新计算。2、动态规划应用方向(能应用该方法解题的问题特征):动态规划用于解决最优化问题。当问题描述中出现“···使得···最好、最优”时,可以思考利用动态规划方法解题。3、动态规划方法介绍:动态规划是付出额外的内存空间来节省时间,典型的时空平衡。3.1、动态规划算法...原创 2020-05-04 17:09:11 · 543 阅读 · 0 评论 -
二叉搜索树(BST)的前驱后继、插入删除函数
二叉搜索树性质:1、左子树上所有结点的值均小于或等于它的根结点的值。2、右子树上所有结点的值均大于或等于它的根结点的值。最大堆性质:1、两个子树上所有节点的值均不大于它的根结点的值。1、前驱与后继:对一棵二叉树进行中序遍历(不是层序),遍历后的顺序,当前节点的前一个节点为该节点的前驱节点;当前节点的后一个节点为该节点的后继节点。1.1 对于二叉搜索树:结点x的前驱节点:小于x.ke...原创 2020-04-23 21:13:16 · 1478 阅读 · 0 评论 -
散列表学习记录
1、直接寻址表:时间复杂度O(1)一个对象的关键字对应表中一个下标,表中存储的指向该对象的指针。**缺点:**若对象关键字很多,导致需要建立的表很大,当存储的对象不多时,空间浪费。2、散列表:时间复杂度O(1)在直接寻址方式下,具有关键字k的元素被存放在槽k中。在散列方式下该元素存放在槽h(k)中;即利用散列函数h,由关键字k计算出槽的位置。这里,函数h将关键字的全域U映射到散列表T[0...原创 2020-04-21 11:40:19 · 151 阅读 · 0 评论 -
选择算法(基于快速排序修改):选择第i小的值
1、选择最大最小值:a)选择最大或最小值,可以遍历数组所有元素,在线性时间O(n)内完成。代码:int findmax(int* A,int N){ int max = A[0]; int tmp; for(int i = 1;i<N;i++){ tmp = A[i]; if(tmp>max){ max = tmp; } } return max;}b)...原创 2020-04-20 18:02:10 · 335 阅读 · 0 评论 -
桶排序(类似计数排序):时间复杂度为O(n)、有稳定性
1、算法假设及描述:2、伪代码:3、应用例子:1000个学生成绩在(0-100)间,因此建立100个桶,将学生按成绩放入桶中。直接按下标放入桶中无需比较,线性时间复杂度O(n)。注:也可以使用计数排序。总结:1、桶排序使用链表存储数据。2、在元素取值范围较小时可以利用计数排序或桶排序。...原创 2020-04-20 11:51:02 · 1202 阅读 · 0 评论 -
基数排序(利用了计数排序):时间复杂度为O(n)、有稳定性
1、原理:对于数组中所有的元素,利用元素每一位的值进行排序,如十进制元素数组[342,254,87],则先对个位排序,再对十位排序,最后对百位排序。由于十进制每一位范围为0-9,因此按位排序的过程调用计数排序。示意图图下:2、伪代码:假设n个d位元素存放在数组A中,其中第一位时低位,第d位时高位。RadixSort(int* A,ind d){ for(int i = 1;i<...原创 2020-04-20 11:32:38 · 6122 阅读 · 0 评论 -
计数排序:时间复杂度为O(n)、有稳定性
基础条件假设: 假设n个输入元素中每一个都是在0-k区间的一个整数。计数排序的基本思想: 对每一个输入元素x,确定小于x的元素个数。这样可以将x直接放在输出数组中的位置上。伪代码:注:1、可以在第二个方框后直接利用各元素个数写出排序后数组,但这样丢失了稳定性;2、而按以上伪代码方式,统计小于或等于下标的元素个数,后逆序处理数组A中个元素位置,则保持了稳定性计数排序的性质:1、时间复...原创 2020-04-19 21:36:12 · 1179 阅读 · 0 评论 -
分治法应用实例二:快速排序
1、基本介绍:实际中最常用的排序算法,期望时间复杂度O(nlgn),且常系数很小。分治理念步骤:2、C++代码及步骤:总结:1、快速排序为最常用的算法。2、通常将数组中最后一个元素作为主元。...原创 2020-04-19 18:26:00 · 354 阅读 · 0 评论 -
各排序算法的最坏与平均时间复杂度
1、原址排序算法:在排序过程中,仅有常数个元素需要存储在待排数组之外,则称该排序算法为原址的。插入排序:常用于小规模输入数组;快速排序:常用于大规模数组排序;归并排序:不是原址排序算法,因为需要开辟一倍空间。2、各排序算法的时间复杂度:...原创 2020-04-19 18:06:30 · 1598 阅读 · 0 评论 -
堆排序算法学习及其应用:优先队列
1、堆介绍:堆排序:时间复杂度为O(nlgn),具有空间原址性;堆中节点高度:该节点到叶节点最长简单路径上边的数目,n个元素的堆可以看作完全二叉树,堆的高度为lg(n)。2、维护堆的性质:让A[i]的值在最大堆中==“逐级下降”==,从而使得以下表i为根节点的子树重新遵循最大堆性质。伪代码:(核心代码段)3、建立最大堆:用自底向上的方法利用过程MAX_HEPITY把一个大小为n的...原创 2020-04-19 15:26:49 · 232 阅读 · 0 评论 -
最大子数组问题:分治法或动态规划法
1、问题: 寻找数组A的和最大的非空连续子数组。我们称这样的连续子数组为 最大子数组。2、使用分治策略的求解思路:作者思路:主观的先用分治法的思路向问题靠近,看问题是否符合分治法的结题过程。该问题的核心:3、伪代码描述:3.1、跨越中点的最大子数组求解过程:FIND_MAX_CROSSING_SUBARRAY(A, low, mid, high){ left_sum = 负无...原创 2020-04-18 10:30:47 · 1326 阅读 · 0 评论 -
分治法和递归的原理及其应用实例:归并排序
1、递归的描述:为了解决一个给定的问题,算法一次或多次递归的调用其自身以解决紧密相关的若干子问题。2、分治法思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。具体步骤:3、归并排序实例:3.1、算法思路:3.2、算法示意图:3.3、代码: ps(代码量大、多看注释行)void MergeSort(int*...原创 2020-04-17 13:18:21 · 823 阅读 · 0 评论 -
RAM指令运行时长
1、一条常规指令执行时间为常量,包括:2、一般指数运算非常量时间:3、指数运算2^k为常量时间:计算机利用左移运算符进行2^k的指数运算。原创 2020-04-13 12:22:50 · 299 阅读 · 0 评论 -
[编程题]统计二进制中1的个数
问题:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。解题思路:因为负数用补码表示,对于负数右移时,在最高位补得是1,因此负数移位位产生无限个1,陷入死循环。出现死循环的错误答案:int NumberOf1_CanNotUse(int n) { int count = 0; while (n != 0) {// 用1和n进行位与运算,结果要是为1则n的2...原创 2020-04-11 14:50:31 · 422 阅读 · 0 评论 -
重建二叉树:根据前序遍历与中序遍历重建二叉树
问题:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。解题思路:因为是树的结构,一般都是用递归来实现。用数学归纳法的思想就是,假设最后一步,就是root的左右子树都已经重建好了,那么我只要考虑将root的...原创 2020-04-11 14:31:40 · 273 阅读 · 0 评论