- 博客(51)
- 收藏
- 关注
原创 Day59 503.下一个更大元素II 42. 接雨水
如何处理循环数组:将两个nums数组拼接在一起,使用单调栈计算出每一个元素的下一个最大值,最后再把结果集即result数组resize到原数组大小就可以了。Resize倒是不费时间,是O(1)的操作,但扩充nums数组相当于多了一个O(n)的操作。也可以不扩充nums,而是在遍历的过程中模拟走了两边nums。单调栈:需要寻找一个元素,右边最大元素以及左边最大元素,来计算雨水面积。
2023-10-24 11:48:15 199
原创 Day58 739. 每日温度 496.下一个更大元素 I
什么时候用单调栈呢?通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
2023-09-10 11:10:46 210
原创 Day57 647. 回文子 516.最长回文子序列 动态规划总结篇
确定dp数组(dp table)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组。
2023-09-10 05:24:20 212
原创 Day56 583. 两个字符串的删除操作 72. 编辑距离
那最后当然是取最小值,所以当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[i][j - 1] + 1 = dp[i - 1][j - 1] + 2,所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
2023-07-17 18:04:21 334
原创 Day55 392.判断子序列 115.不同的子序列
t[j - 1]),此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];if (s[i - 1] == t[j - 1]),那么dp[i][j] = dp[i - 1][j - 1] + 1;dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。
2023-07-16 18:17:41 130
原创 Day53 1143.最长公共子序列 1035.不相交的线 53. 最大子序和
如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]一定是取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]);
2023-07-16 16:44:15 117
原创 Day52 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组
根据dp[i][j]的定义,dp[i][0] 和dp[0][j]其实都是没有意义的!但dp[i][0] 和dp[0][j]要初始值,因为 为了方便递归公式dp[i][j] = dp[i - 1][j - 1] + 1;所以dp[i][0] 和dp[0][j]初始化为0。dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。所以:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
2023-07-14 22:19:36 225
原创 Day51 309.最佳买卖股票时机含冷冻期 714.买卖股票的最佳时机含手续费
【代码】Day51 309.最佳买卖股票时机含冷冻期 714.买卖股票的最佳时机含手续费。
2023-07-13 19:00:37 72
原创 Day50 123.买卖股票的最佳时机III 188.买卖股票的最佳时机IV
dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。一天一共就有五个状态,
2023-07-12 17:55:38 239
原创 Day49 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II
那么第i天持有股票即dp[i][0],如果是第i天买入股票,所得现金就是昨天不持有股票的所得现金 减去 今天的股票价格 即:dp[i - 1][1] - prices[i]。同样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]);如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来。
2023-07-12 12:50:46 83
原创 Day48 198.打家劫舍 213.打家劫舍II 337.打家劫舍III
如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0];p数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]。
2023-07-12 10:15:03 91
原创 Day46 139.单词拆分 关于多重背包,你该了解这些!背包问题总结
确定dp数组(dp table)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组。
2023-05-25 16:24:27 766
原创 Day45 70. 爬楼梯 (进阶) 322. 零钱兑换 279.完全平方数
凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i]),递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j])本题dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j],那么递推公式为:dp[i] += dp[i - j]dp[j]:和为j的完全平方数的最少数量为dp[j]
2023-05-19 10:37:02 75
原创 Day44 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ
第i件物品的重量是weight[i],得到的价值是value[i]。dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加。C++测试用例有两个数相加超过int的数据,所以需要在if里加上dp[i] < INT_MAX - dp[i - num]。本题遍历顺序最终遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。本题和纯完全背包不一样,纯完全背包是凑成背包最大价值是多少,而本题是要求凑成总金额的物品组合个数!
2023-05-19 09:36:38 46
原创 Day43 1049. 最后一块石头的重量 II 494. 目标和 474.一和零
尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。
2023-05-18 16:10:27 95
原创 Day42 01背包问题 二维 01背包问题 一维 416. 分割等和子集
此时dp[j]有两个选择,一个是取自己dp[j] 相当于 二维dp数组中的dp[i-1][j],即不放物品i,一个是取dp[j - weight[i]] + value[i],即放物品i,指定是取最大的,毕竟是求最大价值,所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);所以递归公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
2023-05-17 19:09:06 49
原创 Day41 343. 整数拆分 96.不同的二叉搜索树
从1遍历j,然后有两种渠道得到dp[i]。一个是j * dp[i - j],相当于是拆分(i - j)。dp[i] += dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量]严格从dp[i]的定义来说,dp[0] dp[1] 就不应该初始化,也就是没有意义的数值。i是从3开始,这样dp[i - j]就是dp[2]正好可以通过我们初始化的数值求出来。dp[i] : 1到i为节点组成的二叉搜索树的个数为dp[i]。dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。
2023-05-15 22:33:09 56
原创 Day39 62.不同路径 63. 不同路径 II
62.不同路径 (opens new window)中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了。
2023-05-13 22:53:59 41
原创 Day38 动态规划理论基础 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯
【代码】Day38 动态规划理论基础 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯。
2023-05-12 10:21:33 88
原创 Day37 738.单调递增的数字 968.监控二叉树
从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!大体思路就是从低到上,先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。
2023-05-11 22:15:14 156
原创 Day36 435. 无重叠区间 763.划分字母区间 56. 合并区间
判断重复之后,用合并区间后左边界和右边界,作为一个新的区间,加入到result数组里就可以了。如果没有合并就把原区间加入到result数组。
2023-05-11 20:29:11 38
原创 Day35 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后再按照另一个维度重新排列。按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点,最终按照k的规则完成了队列。遇到感觉没有思路的题目,可以静下心来把能遇到的情况分析一下,只要分析到具体情况了,一下子就豁然开朗了。如果一直陷入想从整体上寻找找零方案,就会把自己陷进去,各种情况一交叉,只会越想越复杂了。如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭。
2023-05-11 18:39:52 36
原创 Day34 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果
贪心的思路,局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。如果将负数都转变为正数了,K依然大于0,那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值和可以达到最大,全局最优:整个 数组和 达到最大。局部最优:当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。全局最优:找到可以跑一圈的起始位置。一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。
2023-05-09 23:35:44 34
原创 Day32 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II
理解本题的关键在于:以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点,这个范围内最小步数一定可以跳到,不用管具体是怎么跳的,不纠结于一步究竟跳一个单位还是两个单位。本题中理解利润拆分是关键点!一旦想到这里了,很自然就会想到贪心了,即:只收集每天的正利润,最后稳稳的就是最大利润了。贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围,覆盖范围内一定是可以跳过来的,不用管是怎么跳的。
2023-05-09 20:36:29 314
原创 Day31 贪心算法理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优,而且想不到反例,那么就试一试贪心。这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计满足小孩数量。贪心的本质是选择每一阶段的局部最优,从而达到全局最优。先遍历胃口,再遍历的饼干,不可以先遍历饼干,再遍历胃口。
2023-05-08 17:23:10 61
原创 Day30 回溯总结 332.重新安排行程 51. N皇后 37. 解数独
组合问题:N个数里面按一定规则找出k个数的集合排列问题:N个数按一定规则全排列,有几种排列方式切割问题:一个字符串按一定规则有几种切割方式子集问题:一个N个数的集合里有多少符合条件的子集棋盘问题:N皇后,解数独等等。
2023-05-07 21:02:40 75
原创 Day29 491.递增子序列 46.全排列 47.全排列 II
是记录本层元素是否重复使用,新的一层uset都会重新定义(清空),所以要知道uset只负责本层!这道题目和46.全排列 (opens new window)的区别在与给定一个可包含重复数字的序列,要返回所有不重复的全排列。本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。所以不能使用之前的去重逻辑!一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。
2023-05-02 22:33:59 60
原创 Day28 93.复原IP地址 78.子集 90.子集II
只要意识到这是切割问题,切割问题就可以使用回溯搜索法把所有可能性搜出来,和刚做过的131.分割回文串 (opens new window)就十分类似了。如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。因为子集就是要遍历整棵树。
2023-05-02 10:57:17 58
原创 Day27 39. 组合总和 40.组合总和II 131.分割回文串
如果是一个集合来求组合的话,就需要startIndex,例如:77.组合 (opens new window),216.组合总和III (opens new window)。回看一下题目,元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。所以我们要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重。最后本题和39.组合总和 (opens new window)要求一样,解集不能包含重复的组合。切割问题的回溯搜索的过程和组合问题的回溯搜索的过程是差不多的。
2023-05-01 17:11:36 148
原创 Day25 216.组合总和III 17.电话号码的字母组合
注意这个index不是 77.组合 (opens new window)和216.组合总和III (opens new window)中的startIndex了。这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
2023-05-01 15:14:49 75
原创 Day24 回溯理论基础 77. 组合
回溯法解决的问题都可以抽象为树形结构,因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度。递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。
2023-05-01 10:29:18 46
原创 Day23 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树
涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。
2023-04-30 10:56:37 81
原创 Day22 235. 二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点
因为是有序树,所有 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。如图,我们从根节点搜索,第一次遇到 cur节点是数值在[p, q]区间中,即 节点5,此时可以说明 p 和 q 一定分别存在于 节点 5的左子树,和右子树中。如果 从节点5继续向左遍历,那么将错过成为q的祖先, 如果从节点5继续向右遍历则错过成为p的祖先。所以当我们从上向下去递归遍历,第一次遇到 cur节点是数值在[p, q]区间中,那么cur就是 p和q的最近公共祖先。,遍历顺序无所谓了)。
2023-04-27 17:19:16 38
原创 Day21 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先
二叉搜索树可是有序的。遇到在二叉搜索树上求什么最值啊,差值之类的,就把它想成在一个有序数组上求最值,求差值,这样就简单多了。在二叉搜素树中序遍历的过程中,也可以直接计算。需要用一个pre节点记录一下cur节点的前一个节点。这题最直观的想法,就是把二叉搜索树转换成有序数组,然后遍历一遍数组,就统计出来最小差值了。使用双指针,只需要遍历一遍二叉搜索树,就求出了众数的集合。
2023-04-27 15:52:25 29
原创 Day20 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树
对于二叉搜索树可就不一样了,因为二叉搜索树的特殊性,也就是节点的有序性,可以不使用辅助栈或者队列就可以写出迭代法。对于一般二叉树,递归过程中还有回溯的过程,例如走一个左方向的分支走到头了,那么要调头,在走右分支。一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。可以递归中序遍历将二叉搜索树转变成一个数组,然后比较一下,这个数组是否是有序的,注意二叉搜索树中不能有重复元素。
2023-04-26 10:34:45 24
原创 Day18 513.找树左下角的值 112. 路径总和 106.从中序与后序遍历序列构造二叉树
可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。可以使用深度优先遍历的方式(本题前中后序都可以,无所谓,因为中节点也没有处理逻辑)来遍历二叉树。如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。递归函数什么时候需要返回值?什么时候不需要返回值?这题要遍历整个树,找到所有路径,所以递归函数不要返回值!本题使用层序遍历要比递归要好理解得多。
2023-04-23 23:10:38 190
原创 Day17 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和
左叶子:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点。这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。
2023-04-23 11:18:16 38
原创 Day16 104.二叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。题目中说的是:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。注意左右孩子都为空的节点才是叶子节点。本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。
2023-04-21 09:38:37 40
原创 Day15 层序遍历 226.翻转二叉树 101. 对称二叉树
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。本题依然是层序遍历,只不过在单层遍历的时候记录一下本层的头部节点,然后在遍历的时候让前一个节点指向本节点就可以了。只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点。
2023-04-20 23:51:10 43
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人