- 博客(53)
- 收藏
- 关注
原创 打卡第六十二天:Floyd算法、A*算法、总结
至此已经讲解了四大最短路算法,分别是Dijkstra、Bellman_ford、SPFA 和 Floyd。
2024-09-05 21:41:10
1739
1
原创 打卡第六十天:Bellman_ford 队列优化算法(又名SPFA)、判断负权回路、单源有限最短路
边:节点2 -> 节点4,权值为1 ,minDist[4] > minDist[2] + (-3) ,更新 minDist[4] = minDist[2] + (-3) = 1 + (-3) = -2。节点1 -> 节点2 -> 节点3 -> 节点1 -> 节点2 -> 节点3 -> 节点4,这样的路径总成本 (-1) + 1 + (-1) + (-1) + 1 + (-1) + 1 = -1。
2024-09-05 20:50:45
1090
原创 打卡第五十八天:拓扑排序、dijkstra
因为 minDist表示 节点到源点的最小距离,所以 新节点 cur 的加入,需要使用 源点到cur的距离 (minDist[cur]) + cur 到 节点 v 的距离 (grid[cur][v]),才是 源点到节点v的距离。未访问过的节点中,源点距离哪些节点最近,怎么算的?至此dijkstra的模拟过程就结束了,根据最后的minDist数组,我们求 节点1 到 节点5 的最短路径的权值总和为 3,路径: 节点1 -> 节点3 -> 节点4 -> 节点5。作为出发节点,它有什么特征?
2024-09-05 20:02:59
792
原创 打卡第五十七天:prim与kruskal算法
最后就生成了一个 最小生成树, 绿色的边将所有节点链接到一起,并且 保证权值是最小的,因为我们在更新 minDist 数组的时候,都是选距离 最小生成树最近的点 加入到树中。minDist数组 也就是记录的是最小生成树所有边的权值。那么我们要求最小生成树里边的权值总和 就是 把 最后的 minDist 数组 累加一起。int v, e;// 填一个默认最大值,题目描述val最大为10000// 因为是双向图,所以两个方向都要填上// 所有节点到最小生成树的最小距离。
2024-09-05 19:46:26
882
原创 打卡第五十六天:冗余连接
,这说明在两条边都可以删除的情况下,要删顺序靠后的边有向树的性质,如果是有向树的话,只有根节点入度为0,其他节点入度都为1(因为该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点)。所以情况一:如果找到入度为2的点,那么删一条指向该节点的边就行了。如图:找到了节点3 的入度为2,删 1 -> 3 或者 2 -> 3。选择删顺序靠后便可。但 入度为2 还有一种情况,情况二,只能删特定的一条边,如图:
2024-09-05 19:29:22
669
原创 打卡第五十五天:并查集理论基础、寻找存在的路径
在第一次查询的时候,相当于是n叉树上从叶子节点到根节点的查询过程,时间复杂度是logn,但路径压缩后,后面的查询操作都是O(1),而 join 函数 和 isSame函数 里涉及的查询操作也是一样的过程。无论使用并查集模板里哪一个函数(除了init函数),都会有路径压缩的过程,第二次访问相同节点的时候,这个节点就是直连根节点的,即 第一次访问的时候它的路径就被压缩了。,将非根节点的所有节点直接指向根节点。我们需要 father[C] = C,即C的根也为C,这样就方便表示 A,B,C 都在同一个集合里了。
2024-09-05 19:23:50
808
原创 打卡第五十三天:字符串接龙、有向图的完全可达性、岛屿的周长
如果我们是处理当前访问的节点,当前访问的节点如果是 true ,说明是访问过的节点,那就终止本层递归,如果不是true,我们就把它赋值为true,因为这是我们处理本层递归的节点。首先明确,本题中什么叫做处理,就是 visited数组来记录访问过的节点,该节点默认 数组里元素都是false,把元素标记为true就是处理 本节点了。此时就要在思考本题的要求了,本题是需要判断 1节点 是否能到所有节点,那么我们就没有必要回溯去撤销操作了,只要遍历过的节点一律都标记上。有递归就有回溯,回溯就在递归函数的下面,为。
2024-08-25 18:12:43
1050
原创 打卡第五十二天:孤岛的总面积、沉没孤岛、水流问题、建造最大岛屿
第二步:再遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。思路依然是从地图周边出发,将周边空格相邻的陆地都做上标记,然后在遍历一遍地图,遇到 陆地 且没做过标记的,那么都是地图中间的 陆地 ,全部改成水域就行。可以 反过来想,从第一组边界上的节点 逆流而上,将遍历过的节点都标记上。遍历每一个节点,是 m * n,遍历每一个节点的时候,都要做深搜,深搜的时间复杂度是: m * n。
2024-08-25 16:52:22
1087
原创 打卡第五十一天:岛屿数量(深搜/广搜)、岛屿的最大面积
本题思路,是用遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都标记上。两种写法,版本一,在主函数遇到陆地就计数为1,接下来的相邻陆地都在dfs中计算。,因为避免了 没有意义的递归调用,在调用dfs之前,就做合法性判断。写法一,dfs只处理下一个节点,即在主函数遇到岛屿就计数为1,dfs处理接下来的相邻陆地。放在的地方,这取决于我们对 代码中队列的定义,队列中的节点就表示已经走过的节点。写法二,dfs处理当前节点,即在主函数遇到岛屿就计数为0,dfs处理接下来的全部陆地。
2024-08-25 13:28:39
535
原创 打卡第五十天:图论理论基础、深度优先搜索理论基础、所有可达路径、广度优先搜索理论基础
二维坐标中,两点可以连成线,多个点连成的线就构成了图。当然图也可以就一个节点,甚至没有节点(空图)整体上一般分为 有向图 和 无向图。有向图是指 图中边是有方向的:无向图是指 图中边没有方向:加权有向图,就是图中边是有权值的,例如:加权无向图也是同理。无向图中有几条边连接该节点,该节点就有几度。例如,该无向图中,节点4的度为5,节点6的度为3。在有向图中,每个节点有出度和入度。出度:从该节点出发的边的个数。入度:指向该节点边的个数。例如,该有向图中,节点3的入度为2,出度为1,节点1的入度为0,出度为2。在
2024-08-25 13:18:40
1062
原创 打卡第四十九天:接雨水、柱状图中最大的矩形
题目文章视频本题暴力解法也是也是使用双指针。首先要明确,要按照行来计算,还是按照列来计算。按照行来计算如图: 按照列来计算如图: 首先,如果按照列来计算的话,宽度一定是1了,我们再把每一列的雨水的高度求出来就可以了。可以看出每一列雨水的高度,取决于,该列 左侧最高的柱子和右侧最高的柱子中最矮的那个柱子的高度。例如求列4的雨水高度,如图:列4 左侧最高的柱子是列3,高度为2(以下用lHeight表示)。列4 右侧最高的柱子是列7,高度为3(以下用rHeight表示)。列4 柱子的高度为1(以下用height表
2024-08-20 21:17:00
948
原创 打卡第四十八天:每日温度、下一个更大元素I、下一个更大元素II
题目说如果不存在对应位置就输出 -1 ,所以result数组如果某位置没有被赋值,那么就应该是是-1,所以就初始化为-1。在遍历nums2的过程中,我们要判断nums2[i]是否在nums1中出现过,因为最后是要根据nums1元素的下标来更新result数组。
2024-08-18 22:03:51
1030
原创 打卡第四十六天:回文子串、最长回文子序列
题目文章视频本题如果我们定义,dp[i] 为 下标i结尾的字符串有 dp[i]个回文串的话,我们会发现很难找到递归关系。dp[i] 和 dp[i-1] ,dp[i + 1] 看上去都没啥关系。要看回文串的性质。 如图:判断字符串S是否是回文,如果知道 s[1],s[2],s[3] 这个子串是回文的,那么只需要比较 s[0]和s[4]这两个元素是否相同,如果相同的话,这个字符串s 就是回文串。那么判断一个子字符串(字符串下标范围[i,j])是否回文,依赖于,子字符串(下标范围[i + 1, j - 1]))
2024-08-17 10:43:55
925
原创 打卡第四十五天:不同的子序列、两个字符串的删除操作、编辑距离
那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});同理dp[0][j] = j;因为 dp[i][j - 1] + 1 = dp[i - 1][j - 1] + 2,所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
2024-08-16 21:32:55
778
原创 打卡第四十四天:最长公共子序列、不相交的线、最大子序和、判断子序列
而是dp[6]。在回顾一下dp[i]的定义:包括下标i之前的最大连续子序列和为dp[i]。最大的连续子序列,就应该找每一个i为终点的连续最大子序列。所以在递推公式的时候,可以直接选出最大的dp[i]。
2024-08-15 22:02:24
1111
原创 打卡第四十三天:最长递增子序列、最长连续递增序列、最长重复子数组
举个例子A[0]如果和B[0]相同的话,dp[1][1] = dp[0][0] + 1,只有dp[0][0]初始为0,正好符合递推公式逐步累加起来。但dp[i][0] 和dp[0][j]要初始值,因为 为了方便递归公式dp[i][j] = dp[i - 1][j - 1] + 1;即当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;根据dp[i][j]的定义,dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。
2024-08-14 20:56:31
800
原创 打卡第四十二天:买卖股票的最佳时机IV、最佳买卖股票时机含冷冻期、买卖股票的最佳时机含手续费
如果i为1,第1天买入股票,那么递归公式中需要计算 dp[i - 1][1] - prices[i] ,即 dp[0][1] - prices[1],那么大家感受一下 dp[0][1] (即第0天的状态二)应该初始成多少,只能初始为0。那么dp[i][0] = max(dp[i - 1][0], dp[i - 1][3] - prices[i], dp[i - 1][1] - prices[i]);今天卖出了股票(状态三),同上分析,dp[0][2]初始化为0,dp[0][3]也初始为0。
2024-08-13 21:56:30
953
原创 打卡第四十一天:买卖股票的最佳时机
同样dp[i][1]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);那么dp[i][0]应该选所得现金最大的,所以dp[i][0] = max(dp[i - 1][0], -prices[i]);一定是选最大的,所以 dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1]);dp[i][1]选 dp[i-1][0] - prices[i],还是dp[i - 1][1]
2024-08-12 21:34:13
1061
原创 打卡第三十九天:打家劫舍I、打家劫舍II、打家劫舍III
题目文章视频当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。决定dp[i]的因素就是第i房间偷还是不偷。如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。如果不偷第i房间,那么dp[i] = dp[i - 1],即考 虑i-1房,(注意这里是考虑,并不是一定要偷i-1
2024-08-10 13:41:48
656
原创 打卡第三十八天:零钱兑换、完全平方数、单词拆分
凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])所以dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的。从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。中可以看出每次dp[j]都要选最小的,
2024-08-09 21:22:11
702
原创 打卡第三十七天:完全背包、零钱兑换II、组合总和IV、爬楼梯(进阶)
dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j]。因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。因为递推公式dp[i] += dp[i - nums[j]]的缘故,dp[0]要初始化为1,这样递归其他dp[i]的时候才会有数值基础。
2024-08-08 21:32:40
678
原创 打卡第三十六天:最后一块石头的重量II、目标和、一和零
题目文章视频本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。本题物品的重量为stones[i],物品的价值也为stones[i]。对应着01背包里的物品重量weight[i]和 物品价值value[i]。确定dp数组以及下标的含义dp[j]表示容量为j的背包,最多可以背最大重量为dp[j]。01背包中,dp[j]的含义,容量为j的背包,最多可以装的价值为 dp[j]。
2024-08-07 21:43:18
709
原创 打卡第三十五天:背包理论基础、分割等和子集
首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。如图:看其他情况。状态转移方程 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);可以看出i 是由 i-1 推导出来,那么i为0的时候就一定要初始化。dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。
2024-08-06 21:15:01
850
原创 打卡第三十四天:不同路径、不同路径II、整数拆分、不同的二叉搜索树
从递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 中可以看出,一定是从左到右一层一层遍历,这样保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值。这里要看一下递推公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。所以递推公式:dp[i] += dp[j - 1] * dp[i - j];
2024-08-05 21:31:57
554
原创 打卡第三十二天:动态规划基础、斐波那契数、爬楼梯、使用最小花费爬楼梯
动态规划,Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的,例如:有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
2024-08-04 21:10:46
1012
原创 打卡第三十一天:合并区间、单调递增的数字、监控二叉树
举个例子,数字:332,从前向后遍历的话,那么就把变成了329,此时2又小于了第一位的3了,真正的结果应该是299。那么空节点不能是无覆盖的状态,这样叶子节点就要放摄像头了,空节点也不能是有摄像头的状态,这样叶子节点的父节点就没有必要放摄像头了,而是可以把摄像头放在叶子节点的爷爷节点上。例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。
2024-08-02 21:21:47
776
原创 打卡第三十天:用最少数量的箭引爆气球、无重叠区间、划分字母区间
此时问题就是要求非交叉区间的最大个数。如图:区间,1,2,3,4,5,6都按照右边界排好序。取 区间1 和 区间2 右边界的最小值,因为这个最小值之前的部分一定是 区间1 和区间2 的重合部分,如果这个最小值也触达到区间3,那么说明 区间 1,2,3都是重合的。接下来就是找大于区间1结束位置的区间,是从区间4开始。区间4结束之后,再找到区间6,所以一共记录非交叉区间的个数是三个。总共区间个数为6,减去非交叉区间的个数3。移除区间的最小数量就是3。
2024-08-01 21:52:16
746
原创 打卡第二十九天:加油站、分发糖果、柠檬水找零、根据身高重建队列
整个插入过程如下:排序完的people: [[7,0], [7,1], [6,1], [5,0], [5,2],[4,4]]
2024-08-01 20:50:33
1130
原创 打卡第二十八天:买卖股票的最佳时机II、跳跃游戏、跳跃游戏II、K次取反后最大化的数组和
i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。而 cover 每次只取 max(该元素数值补充后的范围, cover 本身范围)。如果 cover 大于等于了终点下标,直接 return true 就可以了。
2024-07-30 22:15:31
656
原创 打卡第二十七天:贪心算法理论基础、分发饼干、摆动序列、最大子序和
从代码角度上来讲:遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。很容易可以发现,对于我们当前考虑的这个数,要么是作为山峰(即 nums[i] > nums[i-1]),要么是作为山谷(即 nums[i] < nums[i - 1])。注意版本一的代码中,可以看出来,是先遍历的胃口,在遍历的饼干,那么可不可以 先遍历 饼干,在遍历胃口呢?
2024-07-29 21:19:33
964
原创 打卡第二十五天:递增子序列、全排列、全排列II、重新安排行程、N皇后、解数独
程序运行的时候对unordered_set 频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且每次重新定义set,insert的时候其底层的符号表也要做相应的扩充,也是费事的。拿题目中的示例为例,输入: [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]] ,这是有4个航班,那么只要找出一种行程,行程里的机场个数是5就可以了。
2024-07-27 18:22:19
758
原创 打卡第二十四天:复原IP地址、子集、子集II
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。求排列问题的时候,就要从0开始,因为集合是有序的,{1, 2} 和{2, 1}是两个集合。如果要是全排列的话,每次要从0开始遍历,为了跳过已入栈的元素,需要使用used。不会无限递归,因为每次递归的下一层就是从i+1开始的。
2024-07-27 15:08:26
857
原创 打卡第二十三天:组合总和、组合总和II、分割回文串
切割问题可以抽象为组合问题如何模拟那些切割线切割问题中递归如何终止在递归循环中如何截取子串如何判断回文总结出来难究竟难在哪里也是一种需要锻炼的能力。关于模拟切割线,其实就是index是上一层已经确定了的分割线,i是这一层试图寻找的新分割线除了这些难点,本题还有细节,例如:切割过的地方不能重复切割所以递归函数需要传入i + 1。
2024-07-27 14:49:09
826
原创 打卡第二十二天:回溯算法基础、组合、组合总和III、电话号码的字母组合
例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。然后收集结果,结束本层递归。图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。第一次取1,集合变为2,3,4 ,因为k为2,我们只需要再取一个数就可以了,分别取2,3,4,得到集合[1,2] [1,3] [1,4],以此类推。
2024-07-24 21:30:02
649
原创 打卡第二十一天:修剪二叉搜索树、将有序数组转换二叉搜索树、把二叉搜索树转换为累加树
题目文章视频1、确定参数和返回值有返回值可以通过递归函数的返回值来移除节点。2、确定终止条件修剪的操作并不是在终止条件上进行的,所以就是遇到空节点返回就可以了。3、确定单层递归的逻辑如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。接下来要将下一层处理完左子树的结果赋给root->left,处理完右子树的结果赋给root->right。精简迭代因为二
2024-07-23 21:52:44
818
原创 打卡第二十天:二叉搜索树的最近公共祖先、二叉搜索树中的插入操作、删除二叉搜索树中的结点
从根节点搜索,第一次遇到 cur节点是数值在[q, p]区间中,即 节点5,此时可以说明 q 和 p 一定分别存在于 节点 5的左子树,和右子树中。将删除节点(元素7)的左孩子放到删除节点(元素7)的右子树的最左面节点(元素8)的左孩子上,就是把5为根节点的子树移到了8的左孩子的位置。动画中的二叉搜索树中,删除元素7, 那么删除节点(元素7)的左孩子就是5,删除节点(元素7)的右子树的最左面节点是元素8。终止条件就是找到遍历的节点为null的时候,就是要插入节点的位置了,并把插入的节点返回。
2024-07-22 20:59:51
755
原创 打卡第十八天:二叉搜索树的最小绝对差、二叉搜索树中的众数、二叉树的最近公共祖先
求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。
2024-07-20 16:05:10
1121
原创 打卡第十七天:最大二叉树、合并二叉树、二叉搜索树中的搜索、验证二叉搜索树
最终t1就是合并之后的根节点。因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。要定义一个longlong的全局变量,用来比较遍历的节点是否有序,因为后台测试数据中有int最小值,所以定义为longlong的类型,初始化为longlong最小值。输入的数组大小一定是大于等于1的,所以我们不用考虑小于1的情况,那么当递归遍历的时候,如果传入的数组大小为1,说明遍历到了叶子节点了。
2024-07-20 14:52:46
979
原创 打卡第十六天:平衡二叉树、二叉树的所有路径、左叶子之和、完全二叉树的结点个数、找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树
要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。节点4 的path,在遍历到节点3,path+3,遍历节点3的递归结束之后,返回节点4(回溯的过程),path并不会把3加上。因为题目中其实没有说清楚左叶子究竟是什么节点,那么左叶子的明确定义:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点。判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int使用题目中给出的函数就可以了。
2024-07-19 22:56:45
829
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人