数据结构算法训练
文章平均质量分 76
数据结构算法训练,整理刷题思路。
Orionova
嵌入式软件开发学习分享,学习路径、理论笔记、实践项目等。
展开
-
算法训练 | 图论Part11 | 97. 小明逛公园、127. 骑士的攻击
【代码】算法训练 | 图论Part11 | 97. 小明逛公园、127. 骑士的攻击。原创 2024-07-14 12:52:22 · 310 阅读 · 0 评论 -
算法训练 | 图论Part10 | 95. 城市间货物运输 II、96. 城市间货物运输 III
【代码】算法训练 | 图论Part10 | 94.城市间货物运输、95. 城市间货物运输 II、96. 城市间货物运输 III。原创 2024-07-14 12:48:52 · 243 阅读 · 0 评论 -
算法训练 | 图论Part9 | 94.城市间货物运输 I
【代码】算法训练 | 图论Part9 | prim、kruskal。原创 2024-07-11 14:54:57 · 449 阅读 · 0 评论 -
算法训练 | 图论Part8 | 117. 软件构建、47. 参加科学大会
后面几天都是最短路系列了,对于最短路系列,我的建议是,如果第一次接触最短路算法的话,,二刷的时候 再尝试自己去写出来。三刷的时候,差不多才能把最短路吃透。拓扑排序看上去很复杂,其实了解其原理之后,代码不难。dijkstra(朴素版)精讲。原创 2024-07-11 14:53:10 · 635 阅读 · 0 评论 -
算法训练 | 图论Part7 | 53. 寻宝
【代码】算法训练 | 图论Part5 | prim、ruskal。原创 2024-07-10 00:57:54 · 240 阅读 · 0 评论 -
算法训练 | 图论Part6 | 108.冗余连接、109.冗余连接II
【代码】算法训练 | 图论Part6 | 108.冗余连接、109.冗余连接II。原创 2024-07-10 00:03:31 · 240 阅读 · 0 评论 -
算法训练 | 图论Part5 | 107. 寻找存在的路径
【代码】算法训练 | 图论Part4 | 107. 寻找存在的路径。原创 2024-07-06 19:33:45 · 279 阅读 · 0 评论 -
算法训练 | 图论Part4 | 110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长
【代码】算法训练 | 图论Part4 | 110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长。原创 2024-07-05 11:40:46 · 366 阅读 · 0 评论 -
算法训练 | 图论Part3 | 101.孤岛的总面积、102.沉没孤岛、103.水流问题、104.建造最大岛屿
【代码】算法训练 | 图论Part3 | 101.孤岛的总面积、102.沉没孤岛、103.水流问题、104.建造最大岛屿。原创 2024-07-04 12:45:36 · 330 阅读 · 0 评论 -
算法训练 | 图论Part2 | 99.岛屿数量、100.岛屿的最大面积
【代码】算法训练 | 图论Part2 | 99.岛屿数量、100.岛屿的最大面积。原创 2024-07-03 15:10:14 · 214 阅读 · 0 评论 -
算法训练 | 图论Part1 | 98.所有可达路径
【代码】算法训练 | 图论Part1 | 98.所有可达路径。原创 2024-07-02 20:52:36 · 515 阅读 · 0 评论 -
算法训练 | 单调栈Part2 | 42.接雨水、84.柱状图中最大的矩形
【代码】算法训练 | 单调栈Part2 | 42.接雨水、84.柱状图中最大的矩形。原创 2024-07-02 20:33:26 · 284 阅读 · 0 评论 -
算法训练 | 单调栈Part1 | 739.每日温度、496.下一个更大元素 I 、503.下一个更大元素II
【代码】算法训练 | 单调栈Part1 | 739.每日温度、496.下一个更大元素 I 、503.下一个更大元素II。原创 2024-06-29 15:55:35 · 177 阅读 · 0 评论 -
算法训练 | 动态规划Part13 | 647.回文子串、516.最长回文子序列
其他情况dp[i][j]初始为0就行,这样递推公式:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);整体上是两种,就是s[i]与s[j]相等,s[i]与s[j]不相等这两种。确定遍历顺序:从递归公式中,可以看出,dp[i][j] 依赖于 dp[i + 1][j - 1] ,dp[i + 1][j] 和 dp[i][j - 1]。原创 2024-06-29 03:03:39 · 503 阅读 · 0 评论 -
算法训练 | 动态规划Part12 | 115.不同的子序列、72. 编辑距离
所以当s[i - 1] 与 t[j - 1]相等时,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];dp数组如何初始化:再回顾一下dp[i][j]的定义:dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。当s[i - 1] 与 t[j - 1]不相等时,dp[i][j]只有一部分组成,不用s[i - 1]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1][j]。原创 2024-06-29 02:36:50 · 1149 阅读 · 0 评论 -
算法训练 | 动态规划Part11 | 1143.最长公共子序列、392.判断子序列
确定递推公式:主要就是两大情况: text1[i - 1] 与 text2[j - 1]相同,text1[i - 1] 与 text2[j - 1]不相同如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;dp数组如何初始化:从递推公式可以看出dp[i][j]都是依赖于dp[i - 1][j - 1] 和 dp[i][j - 1],所以dp[0][0]和dp[i][0]是一定要初始化的。原创 2024-06-28 17:31:27 · 570 阅读 · 0 评论 -
算法训练 | 动态规划Part10 | 300.最长递增子序列、674.最长连续递增序列、718.最长重复子数组
但dp[i][0] 和dp[0][j]要初始值,因为 为了方便递归公式dp[i][j] = dp[i - 1][j - 1] + 1;举个例子A[0]如果和B[0]相同的话,dp[1][1] = dp[0][0] + 1,只有dp[0][0]初始为0,正好符合递推公式逐步累加起来。确定递推公式:根据dp[i][j]的定义,dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。即当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;原创 2024-06-28 16:56:09 · 852 阅读 · 0 评论 -
算法训练 | 动态规划Part9 | 188.买卖股票的最佳时机IV、309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费
本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。的进阶版,这里要求至多有k次交易。,本题加上了一个冷冻期在。原创 2024-06-25 12:18:42 · 301 阅读 · 2 评论 -
算法训练 | 动态规划Part8 | 121.买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III
那么第i天持有股票即dp[i][0],如果是第i天买入股票,所得现金就是昨天不持有股票的所得现金 减去 今天的股票价格 即:dp[i - 1][1] - 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]呢?操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]原创 2024-06-25 00:16:32 · 1049 阅读 · 0 评论 -
算法训练 | 动态规划Part7 | 198.打家劫舍、213.打家劫舍II、337.打家劫舍III
可以看出,递推公式的基础就是dp[0] 和 dp[1],从dp[i]的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);对于情况三,取nums[1] 和 nums[3]就是最大的。如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。原创 2024-06-22 20:04:49 · 977 阅读 · 0 评论 -
算法训练 | 动态规划Part6 | 322.零钱兑换、279.完全平方数、139.单词拆分
dp数组如何初始化:从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。确定递推公式:凑足总额为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 中最小的。原创 2024-06-21 21:11:38 · 586 阅读 · 0 评论 -
算法训练 | 动态规划Part5 | 518.零钱兑换 II、377.组合总和 Ⅳ 、70.爬楼梯 (进阶)
确定递推公式:dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导出来。因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。dp数组如何初始化:既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。下标非0的dp[i]初始化为0,因为dp[i]是靠dp[i-j]累计上来的,dp[i]本身为0这样才不会影响结果。原创 2024-06-19 16:54:24 · 674 阅读 · 0 评论 -
算法训练 | 动态规划Part4 | 3. 416.分割等和子集、1049.最后一块石头的重量 II、494.目标和
1049. 最后一块石头的重量 II - 力扣(LeetCode)代码随想录。原创 2024-06-18 20:54:09 · 972 阅读 · 0 评论 -
算法训练 | 动态规划Part2 | 62.不同路径、63.不同路径 II
确定遍历顺序:这里要看一下递推公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。确定遍历顺序:从递归公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 中可以看出,一定是从左到右一层一层遍历,这样保证推导dp[i][j]的时候,dp[i - 1][j] 和 dp[i][j - 1]一定是有数值。机器人从(0 , 0) 位置出发,到(m - 1, n - 1)终点。原创 2024-06-15 16:17:03 · 739 阅读 · 0 评论 -
算法训练 | 动态规划Part1 | 509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯
dp数组如何初始化:看一下递归公式,dp[i]由dp[i - 1],dp[i - 2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。根据dp数组的定义,到达第0台阶所花费的最小体力为dp[0],那么有同学可能想,那dp[0] 应该是 cost[0],例如 cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 的话,dp[0] 就是 cost[0] 应该是1。原创 2024-06-14 14:10:52 · 971 阅读 · 0 评论 -
算法训练 | 贪心算法Part5 | 435.无重叠区间、763.划分字母区间、56. 合并区间、738.单调递增的数字
例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。当确定区间 1 和 区间2 重叠后,取 区间1 和 区间2 右边界的最小值,因为这个最小值之前的部分一定是 区间1 和区间2 的重合部分,如果这个最小值也触达到区间3,那么说明 区间 1,2,3都是重合的。此时问题就是要求非交叉区间的最大个数。区间,1,2,3,4,5,6都按照右边界排好序。原创 2024-06-13 14:37:04 · 853 阅读 · 0 评论 -
算法训练 | 贪心算法Part4 | 860.柠檬水找零、406.根据身高重建队列、452.用最少数量的箭引爆气球
如果真实的模拟射气球的过程,应该射一个,气球数组就remove一个元素,这样最直观,毕竟气球被射了。但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remove气球,只要记录一下箭的数量就可以了。情况一,情况二,都是固定策略,都不用我们来做分析了,而唯一不确定的其实在情况三。按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点,最终按照k的规则完成了队列。情况二:账单是10,消耗一个5,增加一个10。原创 2024-06-12 12:18:59 · 398 阅读 · 0 评论 -
算法训练 | 贪心算法Part3 | 1005.K次取反后最大化的数组和、134.加油站、135.分发糖果
局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果。原创 2024-06-11 14:29:53 · 809 阅读 · 0 评论 -
算法训练 | 贪心算法Part2 | 122.买卖股票的最佳时机II、55.跳跃游戏、45.跳跃游戏II
假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。如果移动下标达到了当前这一步的最大覆盖最远距离了,还没有到终点的话,那么就必须再走一步来增加覆盖范围,直到覆盖范围覆盖了终点。要从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最少步数。原创 2024-06-09 11:22:47 · 535 阅读 · 0 评论 -
算法训练 | 贪心算法Part1 | 455.分发饼干、376.摆动序列、53.最大子序和
实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点。在计算是否有峰值的时候,遍历的下标 i ,计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i]),如果。大尺寸的饼干既可以满足胃口大的孩子也可以满足胃口小的孩子,那么就应该优先满足胃口大的。原创 2024-06-08 23:49:16 · 1330 阅读 · 0 评论 -
算法训练 | 回溯算法Part6 | 51.N皇后、37.解数独
递归单层搜索逻辑:需要的是一个二维的递归 (一行一列),一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!注意这里return false的地方,,因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解,那么会直接返回, 这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去。单层搜索的逻辑:递归深度就是row控制棋盘的行,每一层里for循环的col控制棋盘的列,一行一列,确定了放置皇后的位置。原创 2024-06-06 13:48:05 · 352 阅读 · 0 评论 -
算法训练 | 回溯算法Part5 | 491.递增子序列、46.全排列、47.全排列 II
因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。递归函数参数:元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。排列具有顺序,不可以直接把取过的前面全部去除,只需要记住当前使用的元素,前面的仍然可以用。单层搜索逻辑:同一父节点下的同层上使用过的元素就不能再使用了。原创 2024-06-05 12:30:49 · 533 阅读 · 0 评论 -
算法训练 | 回溯算法Part4 | 93.复原IP地址、78.子集、90.子集II
题目链接:https://leetcode.cn/problems/restore-ip-addresses/原创 2024-06-04 15:36:23 · 465 阅读 · 0 评论 -
算法训练 | 回溯算法Part3 | 39.组合总和、40.组合总和II、131.分割回文串
同一树层,used[i - 1] == false 才能表示,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。此外还定义了int型的sum变量来统计单一结果path里的总和,其实这个sum也可以不用,用target做相应的减法就可以了,最后如何target==0就说明找到符合的结果了,但为了代码逻辑清晰,依然用了sum。因为本题没有组合数量要求,仅仅是总和的限制,所以递归没有层数的限制,只要选取的元素总和超过target,就返回。(这两个参数可以放到函数参数里)原创 2024-06-03 11:27:41 · 1082 阅读 · 0 评论 -
算法训练 | 回溯算法Part2 | 216.组合总和III、17.电话号码的字母组合
遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。(sum参数也可以省略,每次targetSum减去选取的元素数值,然后判断如果targetSum为0了,说明收集到符合条件的结果了,为了直观便于理解,加一个sum参数。例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。注意这个index不是。原创 2024-06-02 15:55:22 · 878 阅读 · 0 评论 -
算法训练 | 回溯算法Part1 | 77.组合、组合优化
回溯法解决的问题都可以抽象为树形结构.因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度。举一个例子,n = 4,k = 4,那么第一层for循环的时候,从元素2开始的遍历都没有意义了。图中每一个节点(图中为矩形),就代表本层的一个for循环,那么每一层的for循环从第二个数开始遍历的话,都没有意义,都是无效遍历。path这个数组的大小如果达到k,说明我们找到了一个子集大小为k的组合了,在图中path存的就是根节点到叶子节点的路径。原创 2024-05-31 11:30:36 · 557 阅读 · 0 评论 -
算法训练 | 二叉树Part9 | 669.修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树
这里定义的是左闭右闭区间,在不断分割的过程中,也会坚持左闭右闭的区间,这又涉及到我们讲过的循环不变量。接着划分区间,root的左孩子接住下一层左区间的构造节点,右孩子接住下一层右区间构造的节点。确定递归终止条件:这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。确定单层递归的逻辑:注意要右中左来遍历二叉树, 中节点的处理逻辑就是让cur的数值加上前一个节点的数值。但在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树。原创 2024-05-30 11:23:52 · 942 阅读 · 0 评论 -
算法训练 | 二叉树Part8 | 235.二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点
剩下的情况,就是cur节点在区间(p->val <= cur->val && cur->val <= q->val)或者 (q->val <= cur->val && cur->val <= p->val)中,那么cur就是最近公共祖先了,直接返回cur。第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点。原创 2024-05-29 10:19:06 · 1053 阅读 · 0 评论 -
算法训练 | 二叉树Part7 | 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数
一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。而且初始化的时候pre = NULL,这样当pre为NULL时候,我们就知道这是比较的第一个元素。结果更新:频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集(以下代码为result数组),因为结果集之前的元素都失效了。存入众数结果:频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中(以下代码为result数组)在二叉搜素树中序遍历的过程中直接计算。原创 2024-05-28 19:40:48 · 378 阅读 · 0 评论 -
算法训练 | 二叉树Part6 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
确定终止条件:因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。确定终止条件:题目中说了输入的数组大小一定是大于等于1的,所以我们不用考虑小于1的情况,那么当递归遍历的时候,如果传入的数组大小为1,说明遍历到了叶子节点了。因为二叉搜索树的节点是有序的,所以可以有方向的去搜索。确定递归函数的参数和返回值:递归函数的参数传入的就是根节点和要搜索的数值,返回的就是以这个搜索数值所在的节点。原创 2024-05-28 18:16:47 · 1013 阅读 · 0 评论