- 博客(27)
- 收藏
- 关注
原创 代码随想录算法训练营第34天 动态规划part02| 题目: 62.不同路径 、 63. 不同路径 II 、343. 整数拆分 (可跳过)、96..不同的二叉搜索树 (可跳过)
从递归公式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]只有这两个方向过来。2.dp[i][j]=dp[i-1][j]+dp[i][j-1]要考虑有障碍,如果i,j是障碍,则本次置0,如果没有障碍再进行推导。
2024-09-04 20:19:45
695
原创 代码随想录算法训练营第32天 动态规划part01| 题目:理论基础 、 509. 斐波那契数 、70. 爬楼梯 、 746. 使用最小花费爬楼梯
那么 dp[0] 应该是多少呢?根据dp数组的定义,到达第0台阶所花费的最小体力为dp[0],那么有同学可能想,那dp[0] 应该是 cost[0],例如 cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1] 的话,dp[0] 就是 cost[0] 应该是1。看一下递归公式,dp[i]由dp[i - 1],dp[i - 2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。
2024-09-03 11:22:55
730
原创 代码随想录算法训练营第31天 | 题目:56. 合并区间 738.单调递增的数字 968.监控二叉树 (可跳过)
例如:98,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]–,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。从前向后遍历的话,遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]减一,但此时如果strNum[i - 1]减一了,可能又小于strNum[i - 2]。一位一位处理,如果不是单调递增的,下一位一定会置9,由于要满足小于n,所以上一位要减一。
2024-09-02 11:38:19
808
原创 代码随想录算法训练营第30天 贪心算法 part04 | 题目:452. 用最少数量的箭引爆气球、 435. 无重叠区间 、763.划分字母区间
可以射出的弓箭的数量没有限制。就是取 区间1 和 区间2 右边界的最小值,因为这个最小值之前的部分一定是 区间1 和区间2 的重合部分,如果这个最小值也触达到区间3,那么说明 区间 1,2,3都是重合的。但仔细思考一下就发现:如果把气球排序之后,从前到后遍历气球,被射过的气球仅仅跳过就行了,没有必要让气球数组remove气球,只要记录一下箭的数量就可以了。直觉上来看,貌似只射重叠最多的气球,用的弓箭一定最少,那么有没有当前重叠了三个气球,我射两个,留下一个和后面的一起射这样弓箭用的更少的情况呢?
2024-08-30 11:48:58
835
原创 代码随想录算法训练营第29天 贪心算法 part03| 题目:134. 加油站 、 135. 分发糖果 、860.柠檬水找零 、 406.根据身高重建队列
判断完右边大于左边后,对于左大于右,需要选择从后向前遍历,以及需要调整最后的结果,取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多,也比右边candyVec[i + 1]的糖果多。如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1。
2024-08-29 16:04:55
585
原创 代码随想录算法训练营第29天 贪心算法 part02| 题目:122.买卖股票的最佳时机II 、 55. 跳跃游戏 、45.跳跃游戏II 、 1005.K次取反后最大化的数组和
与上一题相似,不同的是需要以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点,这个范围内最少步数一定可以跳到,不用管具体是怎么跳的,不纠结于一步究竟跳一个单位还是两个单位。直观想法,尽可能多的将负数反转,如果k在这个过程中小于0,则计算和,如果没有小于0,则将当前数组中最小的正整数处理,如果k为奇数次,则将其反转,偶数次则不做处理。所以真正解题的时候,要从覆盖范围出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最少步数!最后的步数就是最少步数。
2024-08-28 11:27:58
861
原创 代码随想录算法训练营第27天 贪心算法 part01| 题目:理论基础 、455.分发饼干 、376. 摆动序列 、53. 最大子序和
首先声明,长度为2的序列如果不等输出2,大于2时对序列做前后差值并记录,记录的然后对记录的数组进行前后位置相乘,并判断结果,如果<0,则count从初始值1,count+1,直到>=0,此时将count记录并置1,直到所有的遍历所有的数组,比较最大记录的count值,若都<2则输出2,否则输出最大值。并且每块饼干 j,都有一个尺寸 s[j]。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
2024-08-27 17:35:35
591
原创 ## 代码随想录算法训练营第26天 | 题目:491.递增子序列 、46.全排列 、47.全排列 II 、(难题略读)
输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]应该很清晰的看到,树层上对前一位去重非常彻底,效率很高,树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索。输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
2024-08-26 17:26:33
909
原创 代码随想录算法训练营第24天 | 题目:93.复原IP地址 、78.子集 、 90.子集II
相似于40.组合总和,同样需要used数组用作提示数组,当nums[i-1]==nums[i],进行剪枝操作,大体的逻辑是与78.子集 相同的。示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
2024-08-05 11:47:23
598
原创 代码随想录算法训练营第23天 | 题目: 39. 组合总和 40.组合总和II 131.分割回文串
在处理组合问题的时候,递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线。3,单层搜索的逻辑来看看在递归循环中如何截取子串呢?在for (int i = startIndex;i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。首先判断这个子串是不是回文,如果是回文,就加入在vector path中,path用来记录切割过的回文子串。
2024-07-20 13:27:21
626
原创 代码随想录算法训练营第22天 | 题目:回溯算法part01 理论基础、77. 组合 、 216.组合总和III 、 17.电话号码的字母组合
从下图中红线部分可以看出,在集合[1,2,3,4]取1之后,下一层递归,就要在[2,3,4]中取数了,那么下一层递归如何知道从[2,3,4]中取数呢,靠的就是startIndex。第一次取1,集合变为2,3,4 ,因为k为2,我们只需要再取一个数就可以了,分别取2,3,4,得到集合[1,2] [1,3] [1,4],以此类推。示例: 输入: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ],9],所以for循环固定i<=9。
2024-07-17 16:41:19
811
原创 代码随想录算法训练营第21天 | 题目: 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树 总结篇
代码随想录。
2024-07-05 23:27:07
989
原创 代码随想录算法训练营第20天 | 题目: 235. 二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。使用二叉搜索树的性质,当寻找公共祖先,则公共祖先在[p,q]的区间之中,从根节点遍历判断,大于这个区间则向左,小于则向右,直到存在于这个区间中。第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点。
2024-07-02 16:38:01
623
原创 代码随想录算法训练营第19天 | 题目: 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先
在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。我们在二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?那么我们来说一说,如果 root == q,或者 root == p,说明找到 q p ,则将其返回,这个返回值,后面在中节点的处理过程中会用到,那么中节点的处理逻辑,下面讲解。
2024-07-01 11:45:32
727
原创 代码随想录算法训练营第17天 | 题目:654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树
因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。题目中说了输入的数组大小一定是大于等于1的,所以我们不用考虑小于1的情况,那么当递归遍历的时候,如果传入的数组大小为1,说明遍历到了叶子节点了。这表示一个数组大小是1的时候,构造了一个新的节点,并返回。其实本题是同样的道理,我们在寻找一个不符合条件的节点,如果没有找到这个节点就遍历了整个树,如果找到不符合的节点了,立刻返回。
2024-06-29 16:23:40
680
原创 代码随想录算法训练营第16天 | 题目:513.找树左下角的值 112. 路径总和 106.从中序与后序遍历序列构造二叉树
可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。首先明确中序左右中,后序中左右,观察可得后续的最后一位为根节点,对应与中序中的根节点位置,分割左右子树。再根据左右子树分割后序,同时被分割的左右子树的后序重复之前的寻找根节点的方法,实现递归。此时应该注意确定切割的标准,是左闭右开,还有左开右闭,还是左闭右闭,这个就是不变量,要在递归中保持这个不变量。层次遍历,在二叉树:层序遍历登场!
2024-06-28 11:25:52
705
原创 代码随想录算法训练营第15 天 | 题目:110.平衡二叉树 (优先掌握递归)257. 二叉树的所有路径 (优先掌握递归) 404.左叶子之和 (优先掌握递归) 222.完全二叉树的节点个
利用完全二叉树的性质,在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。这个回溯就有很大的问题,我们知道,回溯和递归是一一对应的,有一个递归,就要有一个回溯,这么写的话相当于把递归和回溯拆开了, 一个在花括号里,一个在花括号外。那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这棵树的最大深度,所以才可以使用后序遍历。此时还没完,递归完,要做回溯啊,因为path 不能一直加入节点,它还要删节点,然后才能加入新的节点。
2024-06-26 11:51:18
781
原创 代码随想录算法训练营第13、14 天 | 二叉树的遍历学习、题目: 226.翻转二叉树 (优先掌握递归) 101. 对称二叉树 (优先掌握递归) 104.二叉树的最大深度 (优先掌握递归)111
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。3.确定单层递归的逻辑:先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。
2024-06-25 11:03:27
889
原创 代码随想录算法训练营第12天 | 题目:150. 逆波兰表达式求值 239. 滑动窗口最大值 347.前 K 个高频元素
有的同学可能会想用一个大顶堆(优先级队列)来存放这个窗口里的k个数字,这样就可以知道最大的最大值是多少了, 但是问题是这个窗口是移动的,而大顶堆每次只能弹出最大值,我们无法移除其他数值,这样就造成大顶堆维护的不是滑动窗口里面的数值了。此时我们需要一个队列,这个队列呢,放进去窗口里的元素,然后随着窗口的移动,队列也一进一出,每次移动之后,队列告诉我们里面的最大值是什么。其实队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。
2024-06-24 10:24:55
1064
原创 代码随想录算法训练营第 10天 | 题目:232.用栈实现队列、225. 用队列实现栈 、20. 有效的括号、1047. 删除字符串中的所有相邻重复项
如下面动画所示,用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。所以就是用栈来存放,那么栈的目的,就是存放遍历过的元素,当遍历当前的这个元素的时候,去栈里看一下我们是不是遍历过相同数值的相邻元素。使用栈来模式队列的行为,如果仅仅用一个栈,是一定不行的,所以需要两个栈一个输入栈,一个输出栈,这里要注意输入栈和输出栈的关系。你所使用的语言也许不支持栈。
2024-06-21 15:49:06
654
原创 代码随想录算法训练营第8天 | 题目344.反转字符串、541. 反转字符串II、卡码网:54.替换数字
花式反转主要是对规则的模拟,需要注意,如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。都是对k个字符反转,其操作是相同的。当剩余字符少于 k 个,则end为ch.length - 1,当剩余字符小于 2k 但大于或等于 k 个,end为ch.length - 1。然后通过双指针将字符串扩充,扩充方式如下,采用从前向后的扩充,可以避免后续的移动。给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
2024-06-19 17:26:10
472
原创 代码随想录算法训练营第7天 | 题目454.四数相加II 、 383. 赎金信 、15. 三数之和 、18. 四数之和
四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况,三数之和的时间复杂度是O(n。这么写就是当前使用 nums[i],我们判断前一位是不是一样的元素,在看 {-1, -1 ,2} 这组数据,当遍历到 第一个 -1 的时候,只要前一位没有-1,那么 {-1, -1 ,2} 这组数据一样可以收录到 结果集里。
2024-06-19 16:16:01
803
原创 代码随想录算法训练营第6天 | 题目 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和
其包括一个key和一个value,本题中key存放值,value为下标,map存放遍历过的数组值。需要把字符映射到数组也就是哈希表的索引下标上,因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。依然是使用hash表,可以将target分解为两个数的合,针对hash中一位的数值,寻找target减去其得到的数在hash中是否存在。那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。
2024-06-19 10:10:27
1011
原创 代码随想录算法训练营第4天 | 题目 24. 两两交换链表中的节点 、 19.删除链表的倒数第N个节点 、 142.环形链表II
这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。环形链表的判断应该是双指针,快慢指针都进入环中,当两个指针相等是则有环,两个指针之间的距离是环的大小。如何确定快慢指针在环中一定会相遇,如果slow每次移动一位,快指针一次移动两位,fast相对slow每次移动一位,一定可以追上。简单来说,就是求两个链表交点节点的指针。同样使用双指针,做到一次遍历,设计快指针为慢指针的n+1位置,直到快指针指向null。
2024-06-08 19:19:46
943
原创 代码随想录算法训练营第3天 | 题目:203.移除链表元素、 707.设计链表 、206.反转链表
第一次递归返回时,将 1 -> 2 变为 5 -> 4 -> 3 -> 2 -> 1,并将 1 的 next 设为 null。插入后,新节点将成为链表的第一个节点。第二次递归返回时,将 2 -> 3 变为 5 -> 4 -> 3 -> 2,并将 2 的 next 设为 null。第三次递归返回时,将 3 -> 4 变为 5 -> 4 -> 3,并将 3 的 next 设为 null。示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL。
2024-06-07 15:58:20
843
原创 代码随想录算法训练营第2天 | 数组题目977、 209、 59
1.二分法二分法的核心思想是循环不变量原则,只有在循环中坚持对区间的定义,才能清楚的把握循环中的各种细节。需要注意左闭右闭合左闭右开的区分。2.双指针法即快慢指针,使用一个循环实现两个循环的任务,数组是连续的空间,只能覆盖不能删除,在进行删除数组中某个元素的任务时,快指针进行遍历,不出现对应值时,慢指针值等于快指针值,当出现对应值时,慢指针在这次遍历中不会跟随快指针,即不执行相等,造成延后一位,是得后面的元素覆盖要删除的元素直到最后一位。3.滑动窗口。
2024-06-06 17:19:19
854
原创 代码随想录算法训练营第1天 | 题目704、题目27
35题和702差不多,也是使用二分查找,不同之处在于它考察在未寻找到val时的left和right的关系。这也是薄弱点,我对具体的动态变化不太清楚:寻找过程的变化mid: 1right: 0mid: 0left: 134题没想出来,解题是利用两次二分查找。分别查找左右边界,查找左边界为第一次出现的边界,在查寻到第一次的值时赋值,并向左更新right,确保找到的是第一次出现的值。查询右边界则是找最后出现的值,向右更新left,确保是最后值。
2024-06-05 17:41:16
992
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人