- 博客(38)
- 收藏
- 关注
原创 DAY40|动态规划Part08|LeetCode: 121. 买卖股票的最佳时机 、 122.买卖股票的最佳时机II 、 123.买卖股票的最佳时机III
对于dp[i][0]来说,存在两种情况,一种是第i-1天同样持有股票,另一种是第i-1天不持有股票,在第i天买入,此时dp[i][0] = max(dp[i-1][0],dp[i-1][1] - price[i]);显然,最后的结果一定是dp[5][0]和dp[5][1]中的一个结果,那么应该选择哪一个呢?同理,对于dp[i][1]同样有两种情况,dp[i][1] = max(dp[i-1][1],dp[i-1][0] + price[i]);dp[i][0]和dp[i][1]应该分开计算。
2025-02-24 20:08:39
840
原创 DAY39|动态规划Part07|LeetCode:198.打家劫舍、213.打家劫舍II、337.打家劫舍III
目录LeetCode:198.打家劫舍基本思路C++代码LeetCode:213.打家劫舍II基本思路C++代码LeetCode:337.打家劫舍III基本思路C++代码 看到这个问题,很容易想到,需要对当前房屋偷与不偷两种状态进行判断,而这个状态和前一个房间和前两个房间是否被偷有很大的关系。 通过动规五部曲进行分析: dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。 首先决定dp[i]的因素就是第i房间偷还是不偷。而如果偷
2025-01-09 17:36:32
908
原创 DAY38|动态规划Part06|LeetCode:322. 零钱兑换、279.完全平方数、139.单词拆分
如果选取一维dp数组进行求解,那么dp[j]的取值可以为上一次的dp[j]的取值或者为dp[j-coins[i]]+1,又题目要求的是最小值,因此可以推导出dp[j] = min(dp[j],dp[j-coins[i]] + 1);首先,根据样例提示已知,dp[0] = 0,而对于其他下标对应的值,因为要求最小值,因此我们可以自己设置一个比较大的数值,此时不妨设置为INT_MAX。如果dp[j]为true,并且[j,i]这个区间的子串出现在给定字典中,那么就说明dp[i]一定为true。
2024-12-27 21:22:13
1205
原创 DAY37|动态规划Part05|完全背包理论基础、LeetCode:518. 零钱兑换 II、377. 组合总和 Ⅳ、70. 爬楼梯 (进阶)
dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j])推导出来。因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加。注意:另外在递推公式中提到dp[j] += dp[j - coins[i]],而为了防止相加的数据超过int数据范围,因此要在递推公式前面加上dp[j] < INT_MAX - dp[j-coins[i]]。
2024-12-26 16:19:32
753
原创 DAY36|动态规划Part04|LeetCode:1049. 最后一块石头的重量 II、494. 目标和、474.一和零
力扣代码链接LeetCode:1049. 最后一块石头的重量 II动态规划之背包问题,这个背包最多能装多少?
2024-12-23 18:02:02
679
原创 DAY35|动态规划Part03|LeetCode:01背包问题 二维、01背包问题 一维、416. 分割等和子集
dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j],那么dp[0]就应该是0,因为背包容量为0所背的物品的最大价值就是0。因为一维dp的写法,背包容量一定是要倒序遍历(原因上面已经讲了),如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品。首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。
2024-12-05 15:23:44
865
原创 DAY33|动态规划Part02|LeetCode:62.不同路径 、63. 不同路径 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 - 1][j] + dp[i][j - 1],dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
2024-12-03 21:32:19
882
原创 DAY32|动态规划Part01|LeetCode:509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
对于动态规划的初学者建议先去了解。
2024-12-02 15:35:05
1036
原创 DAY31|贪心算法Part05|LeetCode:56. 合并区间、738.单调递增的数字
以示例三的数字来举例,从后向前进行遍历,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,重复利用上次比较得出的结果,从后向前遍历332的数值变化为:332 -> 329 -> 299。先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同。即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。
2024-11-17 19:40:44
456
原创 DAY30|贪心算法Part04|LeetCode:452. 用最少数量的箭引爆气球、435. 无重叠区间、763.划分字母区间
另外我们还需要对两个区间的终止位置进行比较,取最小值并赋给变量end,end就是区间分割点,这样当和下个区间相比较时,就可以判断三个区间是否存在公共区间,并且用count用来记录重叠区间的个数。那么按照气球起始位置排序,还是按照气球终止位置排序呢?按照左边界进行排序,我们依旧按照从前向后进行遍历,如果遍历到当前区间的起始位置大于上一个区间的终止位置就说明存在重叠区间,即进行记录。可以看出首先第一组重叠气球,一定是需要一个箭,气球3,的左边界大于了 第一组重叠气球的最小右边界,所以再需要一支箭来射气球3了。
2024-11-15 17:59:07
1086
原创 DAY29|贪心算法Part03|LeetCode:134. 加油站、135. 分发糖果、860.柠檬水找零、406.根据身高重建队列
回归本题,整个插入过程如下:排序完的people: [[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
2024-11-14 18:49:52
780
原创 DAY28|贪心算法Part02|LeetCode:122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II、1005.K次取反后最大化的数组和
i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。而 cover 每次只取 max(该元素数值补充后的范围, cover 本身范围)。那我们怎么判断是否可以达到最后一个下标呢?
2024-11-13 15:39:17
1007
原创 DAY27|贪心算法Part01|LeetCode:455.分发饼干、376. 摆动序列、53. 最大子序和
在做一个题目的时候,靠自己手动模拟,如果模拟可行,就可以试一试贪心策略,如果不可行,可能需要动态规划。那么什么时候可以使用贪心算法呢?。
2024-11-12 19:06:04
1298
原创 DAY25|回溯算法Part04|LeetCode:491.递增子序列、46.全排列、47.全排列 II
可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。题目要求递增子序列大小至少为2,而且不会无限递归,可以不加终止条件,startIndex每次都会加1,for循环结束即会终止。排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。中我们是通过排序,再加一个标记数组来达到去重的目的,而本题中是不能对原数组进行排序的,排完序的数组都是自增子序列了。这个题目和上一题的区别在于。
2024-11-12 10:44:42
548
原创 DAY24|回溯算法Part03|LeetCode:93.复原IP地址、78.子集、90.子集II
如果合法就加上' . ',递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符。startIndex表示集合搜索的位置,那么如果startIndex超过了nums的size,不就说明没有元素可取了,也就可以停止循环了,但其实本来。参数:startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。从图中可以看出,同一树层上重复取2就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!回溯的时候,就将刚刚加入的分隔符。
2024-11-10 15:12:54
1193
原创 DAY23|回溯算法Part02|LeetCode: 39. 组合总和 、40.组合总和II 、131.分割回文串
对于sum已经大于target的情况,其实是依然进入了下一层递归,只是下一层递归结束判断的时候,会判断sum > target的话就返回。在处理组合问题的时候,递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线。本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。参数:本题递归函数参数还需要startIndex,因为切割过的地方,不能重复切割,和组合问题也是保持一致的。,那么“使用过”在这个树形结构上是有两个维度的,
2024-11-09 15:06:03
948
原创 DAY22|回溯算法Part01|LeetCode: 77. 组合、216.组合总和III 、17.电话号码的字母组合
参数:题目中给的string digits,然后还要有一个参数就是int型的index,这里的Index不是前面的startIndex,这里的两个字符串不属于同一个数组,用来记录遍历到第几个字符。参数:定义目标和targetSum(int类型)(即题目中的n),定义k,定义已经收集的元素的总和sum,也就是path里元素的总和,定义下一层for循环搜索的起始位置startIndex。在上面我们提到了,回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度。
2024-11-07 23:14:28
1062
原创 DAY21|二叉树Part08|LeetCode: 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树
目录LeetCode: 669. 修剪二叉搜索树基本思路C++代码LeetCode: 108.将有序数组转换为二叉搜索树基本思路C++代码LeetCode: 538.把二叉搜索树转换为累加树基本思路C++代码 这个题目比较简单,但是一定要注意遇到节点在目标区间以外,不能直接返回null,而是应该继续向下判定,因为对于一个搜索二叉树来讲,在遍历整个二叉树的节点的过程中,如果某个节点的值小于区间的最小值,对于该节点的左子树中的所有节点一定都小于目标区间的最小值,但是右子树中却可能存在符合目标区间的
2024-11-06 17:01:51
758
原创 DAY19/20|二叉树Part07|LeetCode: 235. 二叉搜索树的最近公共祖先 、 701.二叉搜索树中的插入操作 、450.删除二叉搜索树中的节点
因为是有序树,所以 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。如果当前节点的值大于p和q,说明p,q应该在当前节点的左子树中,继续向左遍历,同理当前节点的值小于p和q,继续向右遍历,否则说明当前节点即为最近公共祖先。参数:首先需要传入一个指针指向当前遍历的节点,还需要传入一个删除值key,为int类型。参数:需要传入一个指向当前节点的指针,以及两个分别记录目标节点的指针。参数:传入一个指针指向当前节点,传入需要插入的节点的值,类型为int。
2024-11-05 20:17:27
780
原创 DAY18|二叉树Part06|LeetCode: 530.二叉搜索树的最小绝对差、501. 二叉搜索树中的众数、236.二叉树的最近公共祖先
2024-11-04 19:27:15
1121
原创 DAY17|二叉树Part05|LeetCode: 654.最大二叉树 、617.合并二叉树 、700.二叉搜索树中的搜索、98.验证二叉搜索树
我们只需要定义一个新数组,用来记录分割后的左(右)子数组,由于题目说了输入数组的大小大于等于1,因此只需要考虑子数组的大小是否为1即可,当等于1的时候说明是叶子节点,就可以返回了。因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。并且子树也符合这种特性。返回值:我们在寻找一个不符合条件的节点,如果没有找到这个节点就遍历了整个树,如果找到不符合的节点了,立刻返回,因此为bool类型。
2024-11-02 21:35:02
816
原创 DAY16|二叉树Part04|LeetCode: 513.找树左下角的值、112. 路径总和、106. 从中序与后序遍历序列构造二叉树
使用层序遍历当然是可以的,而如果使用递归的方法可以使用前序遍历(当然中序,后序都可以,因为本题没有中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。中序数组我们都切成了左中序数组和右中序数组了,那么后序数组就可以按照左中序数组的大小来切割,切成左后序数组和右后序数组。
2024-11-01 19:47:54
717
原创 DAY15|二叉树Part03|LeetCode: 222.完全二叉树的节点个数、110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和
最重要的是要确定二叉树中哪些节点是左叶子,如果一个节点的左右孩子为空,那么我们就可以认为这个节点是叶子节点,那么在这个基础上进行延伸,如果一个节点有左孩子,并且左孩子的左右孩子都为空,那么这个节点的左孩子不就是所谓的左叶子节点了吗?当节点为空时,说明节点数量为0,返回0,然后需要对当前子树是否为满二叉树进行判断,因为满二叉树一定是完全二叉树,而满二叉树的节点数量很好计算,为2^n-1,其中n为二叉树的深度。对二叉树的所有节点进行遍历,如果节点为空时,就返回零,说明此时不存在左叶子节点。
2024-10-30 19:43:35
1049
原创 DAY14|二叉树Part02|LeetCode: 226.翻转二叉树、101. 对称二叉树、104.二叉树的最大深度、111.二叉树的最小深度
熟悉的递归法三部曲:确定递归函数的参数和返回值。参数需要加入的参数为二叉树的根节点,返回值是二叉树的最小深度,因此为int类型。
2024-10-29 20:18:07
831
原创 DAY11|栈与队列Part02|LeetCode: 150. 逆波兰表达式求值 、 239. 滑动窗口最大值、 347.前 K 个高频元素
如果用大顶堆,也就是当前频率最大的元素在堆顶,那么我们想要push进一个元素,我们就必须pop掉一个元素,我们应该是想pop掉当前k个元素中,频率最小的那个元素。对于优先级队列来讲,可以将滑动窗口内部的元素进行排序,但是排序后我们失去了原来的顺序,这样每次弹出的是最大值,而无法移除其他的元素,因此应该考虑使用单调队列。,这样就可以保证队列中的数值从大到小,并且如果队列中的数值都小于push的数值,可以证明新push的值就是当前滑动窗口的最大值,即可将当前值push进队列,并将之前队列中的数值pop。
2024-10-26 21:21:30
644
原创 DAY10|栈与队列Part01|LeetCode: 232.用栈实现队列 、225. 用队列实现栈、20. 有效的括号、1047. 删除字符串中的所有相邻重复项
根据上一个题的思想,很容易想到,通过定义两个队列,其中一个队列进行辅助来解决这个题目,我们可以计算这个队列中元素的个数n,将前n-1个元素放到辅助队列中,剩下的那个既可以看作是堆栈中栈顶元素。这道题和上一题(有效的括号)思想相同,都可以通过构建一个堆栈,遍历字符串中的元素,并将元素与栈顶元素进行判断,如果该元素与栈顶元素相同,则拿出栈顶元素并进入下一次循环,否则将元素压入堆栈。那么进一步,我们可以只用一个队列来完成题目嘛?和上面的逻辑一样,但是一定要记住将队首的元素弹出后一定要重新添加到队尾。
2024-10-25 16:59:51
1064
原创 DAY09(1)|字符串Part02|LeetCode:151.翻转字符串里的单词、卡码网:55.右旋转字符串
(当然可以使用split函数对单词进行分隔,但是这样就失去了他的意义)。我们可以考虑先把整个字符串进行倒序,但是这样单词本身也倒序了,最后再把每个单词再进行一次倒序,就能完成我们的目的。如果不仔细琢磨一下erase的时间复杂度,还以为以上的代码是O(n)的时间复杂度呢。想一下真正的时间复杂度是多少,这个题和上个题目很像,同样可以看成是整体翻转+局部翻转的展开。举个例子,源字符串为:"the sky is blue "逻辑很简单,从前向后遍历,遇到空格了就erase。
2024-10-24 15:50:05
442
原创 DAY08|字符串Part01|LeetCode:344.反转字符串、541.反转字符串||、卡码网:54.替换数字
很像,在反转链表时我们使用了双指针的方法,那么对于本题我们依旧可以使用双指针的方法,不同的是对于链表我们通过改变节点的next指针指向的方向从而实现链表的反转,而字符串的反转其实更为简单,使用左右两个指针,直接对指针指向的字符进行位置调换即可。这里有人就想说,那我直接使用C++自带的reverse库函数,一行代码不就可以搞定了,其实不然。在笔试的时候,出这样的题目显然是想考验对反转字符串的原理是否明白,如果在现场面试中,我们什么时候使用库函数,什么时候不要用库函数呢?看到这个题,其实和前面做过的。
2024-10-23 15:51:24
498
原创 DAY07|哈希表Part02|LeetCode:454.四数相加II、383.赎金信、15. 三数之和、18.四数之和
正确答案是[-2, 2, 0]和[-2, 1, 1]。两层for循环就可以得到a+b的值,并且通过使用哈希法判断0-(a+b是否在集合中出现过),这个思路确实没有问题,但是由于题目中明确说了答案中不可以包含重复的三元组,而把符合条件的三元组放到vector中再去重非常浪费时间非常复杂,很容易超时。这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于题目18. 四数之和,题目15.三数之和,还是简单了不少!
2024-10-22 21:52:10
1053
原创 DAY05-06|哈希表Part01|LeetCode:242.有效的字母异位词、349.两个数组的交集、202.快乐数、1.两数之和
今天自己做的效果并不好,容器的知识有较多忘记了,要尽快复习。另外做题前应该首先明确什么情况下需要使用哈希表的方法,什么时候应该使用数组、set还是map的结构。
2024-10-21 15:58:20
607
原创 代码随想录算法训练营DAY04|链表Part02|LeetCode: 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II
第二题一开始的思路存在点问题,导致花费了挺长时间,看懂第二题以后,第三题就比较容易想到使用双指针法。第四题确实需要一定的数学方法,特别是为什么第一次在环中相遇,慢指针的步数 是 x+y 而不是 x + 若干环的长度 + y,这一题需要多多回顾!
2024-10-19 15:54:33
1108
原创 代码随想录算法训练营DAY03|链表Part01|LeetCode:203.移除链表元素 、707.设计链表、206.反转链表
int val;//构造链表节点今天的题目前两个比较简单,最后一题没有想到,特别是递归的方法很简短,但是需要很强的逻辑能力,以后需要多在这方面进行锻炼。
2024-10-18 16:10:55
913
原创 代码随想录算法训练营DAY02|数组Part02|LeetCode:209.长度最小的子数组、59.螺旋矩阵II
关于此题涉及的滑动窗口法,我看到了一个很有趣的解释:可以理解为左右指针中间窗口的sum为两指针的“共同财产”,右指针一直在努力工作挣钱,好不容易共同财产大过target,记录一下两指针之间的距离,然后左指针就开始得瑟挥霍,不停花钱(往右移动),结果花钱一直花到sum又小过target,此时右指针不得不再次出来工作,不停向右移动,周而复始,最后取左右指针离得最近的时候的值。今天的题目相对于昨天的题目难度变化不大,更多的是想法层次上的转变,另外今天的题目让我意识到边界条件的判定还存在较大的不足。
2024-10-17 14:38:57
789
原创 代码随想录算法训练营DAY01|数组Part01|LeetCode:704 二分查找、27 移除元素 、977 有序数组的平方
双指针的用法还有待提高,扎扎实实搞清楚每一个知识点。
2024-10-16 15:33:17
1036
2
原创 Linux系统中的CMake使用教程
在平时的编译过程中,如果源文件比较少的时候可以选择直接使用GCC进行编译,但是当构建一个项目时,会需要同时对许多文件进行编译,此时我们使用CMake进行编译就会简单很多,最近也学习了一些CMake的知识想和大家进行一下分享。CMake 是一个项目构建工具,并且是跨平台的。关于项目构建我们所熟知的还有Makefile(通过 make 命令进行项目的构建)。但是如果自己动手书写makefile,其工作量很大而且通常会依赖当前的编译平台,解决依赖关系的时候也容易出现很多错误。
2024-04-29 12:17:32
2753
2
原创 关于slam十四讲中opencv安装报错以及解决方案
会出现:E:软件包 libvtk5-dev 没有可安装候选E:软件包 libtiff4-dev 没有可安装候选解决方法:将代码改为然后对软件源进行更新:此时就可以成功安装了。
2024-04-25 16:53:23
1454
6
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人