- 博客(121)
- 收藏
- 关注
原创 763. 划分字母区间
直接理解这个代码思路如下随着对s进行遍历,不断地更新end,end是此次区间划分右边界至少要到达的位置,因为一个字母只能出现在一个区间中,那么一次区间划分一定要包含该字母最后出现的位置。进行一次区间划分的条件是i==end,这意味着,在i到达end前,如果有其他字母最后出现的位置超过了当前end,就要扩宽当前end。当i==end时进行此次区间划分,就可以保证本区间内出现的字母绝对不会出现在其他区间中。
2023-07-18 16:58:49
125
原创 435. 无重叠区间
先排序,然后开始遍历,如果当前区间和上一个有重叠,那就去掉右边界值较大的那个区间。因为右边界值较大更容易与后面的区间发生重叠。只能说贪心还真他娘的没什么道理。
2023-07-18 16:38:20
119
原创 452. 用最少数量的箭引爆气球
不断记录最小的右边界,当当前气球的左边界大于此前遍历过的所有气球的最小右边界,那么这箭可以射穿之前的所有气球,而当前气球就射不穿,因此result+1。先将左边界从小到大排序,沿着左边界开始向右编列。
2023-07-10 17:37:11
137
原创 406. 根据身高重建队列
遍历到到当前人时,他前面的所有人一定比他高(因为排过序),那只需要关注p[1],即需要前面有几个比他高的,就把他插到哪里。而由于他比前面所有人都低,因此他无论插在哪里,前面所有人的p[1]值仍是满足题意的。因此只需要一个一个处理就能达到最后的全局最优。题看不懂,看了随想录,简直是绝绝子的思路。
2023-07-10 17:06:27
93
原创 860. 柠檬水找零
我这里是先判断手里有没有五块,没有就直接g,有的话尝试再来一张10块,有10块就ok,没10块再尝试使用三张五块。贪心的点就在于优先使用10块去解决收到20时的找钱问题。简单题,关键在于对收到20情况的处理,
2023-07-05 15:54:24
46
原创 135. 分发糖果
意思是甲>乙时,向右遍历时,乙会得到一个糖果,向左遍历时甲一定比乙多一个糖果,最终的糖果数即为乙得到了n颗,甲得到了至少n+1颗。甲=乙时其实是无所谓的,无论甲乙拿到多少糖果都是满足题意的。因此这样遍历两次后,可以保证任意相邻的两个孩子,都是得分高的那个孩子拿到的糖果多。这个题看完随想录的视频,感觉是妙蛙种子,但不道是为啥。
2023-07-05 15:33:17
69
原创 134. 加油站
其实贪心1有助于理解贪心2中为什么totalsum>0就一定可以完成循环。当情况1与情况2都不满足时,意味着totalsum>0但是从0站开始循环的过程中中间某站出现了累加和小于0。那么我们从后往前找到某一个rest = gas[i] - cost[i],即从这个站台出发可以余下rest的油,此时起始量为rest那么到达之前累加和为负的那个站点时,油量比从0站点出发多出rest。只要出现累加油量小于0,那么此前的所有站都不能作为出发点(以此前任意站为出发点,到当前站时累加油量一定是负)
2023-07-03 11:37:16
60
原创 1005. K 次取反后最大化的数组和
贪心其实很简单,每次找值最小的进行取反,如果最小的值是负数,那么可以得到最大的提升,如果最小值是非负数,那么可以得到最小的下降。第三步是如果还有剩余步数(此时nums是一个降序排列的全为正数的数组),那么就尽可能将最小的正值进行取反即可。leetcode中进行排序要比找最小值的下标更快。第二步是花费次数尽可能地将其中最小的负值取反。随想录中是按绝对值进行降序排列,
2023-07-03 11:03:52
42
原创 55. 跳跃游戏
其实在整个循环过程中也是一种遍历,即只要当前 i 没有超过cover覆盖的范围,那就试一试i+nums[i]有没有超出cover(如果超出那就说明cover的范围被进一步扩大了)这题就是怎么跳无所谓,只要找到最远能跳到哪里去。发现贪心的问题都是贵在想法。
2023-07-03 10:05:55
47
原创 122. 买卖股票的最佳时机 II
等价于[price(4)-price(3)]+[price(3)-price(2)]+[price(2)-price(1)]如[3,9,5,7],在第一天买入第四天卖出,总收益是price(4)-price(1)=4,重点就是无论你选择那天买入,那天买出,都可以通过把负收益扔出去来更大化这笔收益,因此,任给一段日期的收益,我们可以通过上述的分解与优化方式来实现收益最大化。优化方式是改为第一天买入第二天卖出,第三天买入第四天卖出,收益可以提升到8。
2023-06-30 16:40:49
45
原创 53. 最大子数组和
这句话我相信是较好理解的,如果子序列的开头是一个cursum<0的子序列,那我们把这个开头子序列去掉,剩下的子序列的和绝对不会减小。这也就是为什么我们要从头开始遍历,一旦遍历到cur<=0,我们直接舍弃当前遍历到的所有元素。本题中cur记录了一串子序列的累加和。真的是贪心的妙处要慢慢体会。
2023-06-29 10:57:58
45
原创 51. N 皇后
关于isvalid函数我的思路是,当前行落子时,上面的行里面是有皇后的,所以需要找当前位置的正上方,右上方和左上方有没有皇后,正上方好说,关键是右上方和左上方,以左上方为例,当前的位置是(i,j)那么左上方一共有min(i,j)个格子需要判断是否有皇后,此后的思路就很简单了,初始化一个n*n的列表作棋盘,落子就在该位置置为1,拿起就将该位置回归为0,以此作为回溯的思路。看了一眼随想录,后面就是自己写的了,n皇后其实也就那样┭┮﹏┭┮。然后就遍历这r3个格子,注意往左上方走i-k,j-k。
2023-06-28 17:07:15
45
原创 332. 重新安排行程
其他的都还好,关键在于递归函数return的内容,前面回溯算法中,只在终止条件中进行了return,本题在递归逻辑中也有return,旨在找到一条路径直接返还,保证题目要求中的(如果存在多种有效的行程,请你按字典排序返回最小的行程组合。这个递归的逻辑还是很妙的,当path数量不够,但从当前机场出发已经没有票了,就不会进入for循环,递归函数直接返还False,那么对于上层递归而言if self.backtracking():语句内的内容不会执行,于是函数向下执行,把当前机场抛出并恢复用过的机票。
2023-06-28 11:29:26
47
原创 47. 全排列 II
这是因为本层冲已经用过某一个元素值了如果本层重复选此元素值会导致最终结果中出现完全一样的组合。用counter一直与path相伴随,path中添上什么,counter中就减去什么。所谓横向去重与纵向去重。
2023-06-28 10:15:49
49
原创 491. 递增子序列
注意子序列不是子集,对于子集而言,子集中元素的顺序没有必要与原集合元素的顺序保持一致。而子序列要求其中元素的顺序也要与子集保持一致,因此这个题不能是单纯的像上个题一样加一个终止条件只回收长度大于2的子集。因为要拿到子序列,这意味着原序列不能进行排序,而原序列中有重复元素,那么处理去重时不能使用if判断,换而使用集合used=set()进行去重。此外由于只要递增序列,那么向path中添加新的元素值之前,必须要保证新的元素值大于path中最后一个元素值才能放入path中。
2023-06-28 09:37:24
53
原创 93. 复原 IP 地址
递归逻辑中,如果s[startindex] == ‘0’,那么这层递归不需要循环,因为在此次分割中,只有分割出一个’0’是合法的,后续以0开头的长度大于1的字符串都是不合法的。如果s[startindex]!= ‘0’,那么就正常进入循环。因为要求一定是切成4段,所以终止条件的设计思路是,如果已经切到末尾,切出了4段则ok,没切出四段则舍弃,如果没切到末尾,且已经有三段了,那也没必要再循环了,剩下的部分一股脑当作第四段就可以了。
2023-06-27 14:26:29
46
原创 131. 分割回文串
一个简单的改进就是在遍历时只要发现不一样直接返还False,避免每次都对字符串进行完整的遍历。那么只用查询isPalindrome[i][j]就直到s[i:j+1]是不是回文串。用两个指针从字符串两端向中间遍历,最后用all函数判断是否全为True。用一个n*n的矩阵,i,j记录s[i:j+1]是不是回文串。极速版回文串判断(哈希)用all函数判断回文串。
2023-06-27 13:25:39
45
原创 40. 组合总和 II
如数组[1,1,2,3,4]选择1,2,3(第一个1)与1,2,3(第二个1)和都为6,虽然两个1是不同的元素,但是两个1,2,3是相同的组合。因为数组中有重复的数,因此在组合时需要考虑如何剪枝去重。
2023-06-27 12:16:18
36
原创 39. 组合总和
这一题要求数组中的元素可以重复使用,但需要是不同的组合,例如[3,2,2]与[2,2,3]是同一个组合。这里与传统的组合问题的差异就在于,传统组合问题,在循环中进入递归时,startindex = i + 1(从当前遍历位置的下一个元素开始遍历)。如果元素可以重复使用,那就startindex = i(从当前遍历位置开始下一次遍历)。剪枝版的优势在于对数组进行升序排列后,当数组中一个元素添加到path中,cursum > target,则此元素后面的所有元素都大于此元素,也就没有必要继续遍历了。
2023-06-27 11:54:20
35
原创 77. 组合
当进入for循环时,已知的是path的长度,这是已经记录在案的内容,题目要求的长度是k,那此时,还需要k-len(path)个数,当i=n-(k-len(path))+1,从当前i的值算起,到n为止,正常还有k-len(path)个数,但当i=n-(k-len(path))+2时,从当前i算起,到n,只剩下k-len(path)-1个数,就算把他们全扔进path中,也达到不了len(path)==k这个终止条件,这意味着这条路径绝对返还不了有用的结果,那就提前裁剪掉。端午节假后回归┭┮﹏┭┮。
2023-06-26 11:02:33
36
原创 538. 把二叉搜索树转换为累加树
右中左遍历,记下累加和,遍历到中的时候累加即可。1038. 从二叉搜索树到更大和树。538.把二叉搜索树转换为累加树。
2023-06-17 00:50:34
43
原创 669. 修剪二叉搜索树
getin的功能是给定根节点,从根节点开始遍历,直到找到节点的值在low与high之间,以此节点为新的根节点,其他节点全部都舍弃掉(因为这个过程像是在找low与high的最近公共祖先,所以叫getin)当当前val大于high时,返还其左子树剪枝后的结果(因为并不能保证左子树全部都能要)然而根节点在low与high之间并不能保证其子节点也全部满足,因此要继续遍历。cutit的功能是从getin得到的跟节点开始递归。这个递归的逻辑比较复杂。
2023-06-16 23:39:28
38
原创 450. 删除二叉搜索树中的节点
之后是递归的逻辑,如果当前节点是待删除节点,返还删除当前节点后的新节点,如果当前节点不是待删除节点,遍历当前节点的左节点或右节点,同时返还值是当前节点。1.待删除节点的右节点不为None,则将其左节点接到右节点的最左侧,然后将右节点连到删除节点的父节点即可。本来我的考虑是如果要删除当前节点,应当要拿到当前节点的父节点才行,但实际上只能说递归真的很神奇。2.待删除节点的右节点不存在为None,则直接将左节点连到删除节点的父节点即可。首先是递归的返还条件是遇到空节点。
2023-06-16 22:22:02
39
原创 701. 二叉搜索树中的插入操作
当执行到root.left/right = TreeNode(self.val)后,就在当前节点插入新节点,然后就停止了(这样会不会递归的堆栈没返还呀)这个递归没返还条件==
2023-06-16 21:27:50
42
原创 236. 二叉树的最近公共祖先
当到达最近祖先之前,左右孩子向中传递一边传递的是p/q另一边传递的是None,当到达最近祖先时,此节点左孩子传的是p/q,右孩子传的是q/p,此时此节点向上返回的是自己的最近祖先root,再之后节点左右孩子一边返还祖先root一边返还None,此时节点向上返还祖先root。关键不在于递归的终止条件,而在于递归的单步逻辑。
2023-06-16 21:27:11
48
原创 235. 二叉搜索树的最近公共祖先
好tmd精简,因为这里每次递归只选择向左或向右,所以直接一条路走到最近公共祖先。记住只要遇到root.val在p与q之间,这个root就一定是最近公共祖先。其他情况跟下一题有点类似。自写版,递归的思路是。遇到公共祖先节点返还。
2023-06-16 20:47:17
43
原创 501. 二叉搜索树中的众数
几个细节,如果计数器等于max时result是append,如果计数器大于max此时要把result清0再append。
2023-06-15 15:12:10
34
原创 530. 二叉搜索树的最小绝对差
其中有一个处理的细节是self.val的处理,在遍历到第一个中值时,要记录它的val值对self.val进行初始化,因为现在没有差的概念,所以此时只执行self.val = root.val而self.min依然保持inf。随想录中是用per = root的策略来实现双指针,我没有用per双指针来跟随root指针。仍然是中序遍历,用一个全局变量self.val记录上一个遍历节点的值。
2023-06-15 14:10:05
40
原创 98.验证二叉搜索树
本代码相对于随想录中的版本,在得到isleft后如果isleft == False,就直接返还当前节点不是二叉搜索树,这样可能减少遍历的次数,如果当前节点的左节点已经不是二叉搜索树了就不会再遍历其右节点了。因此只需要记录下来遍历过的值的最大值,则当前遍历值必须大于这个最大值,否则以当前节点为根节点的二叉树就不是二叉搜索树,返回False即可。注意左中右中序遍历二叉搜索树时,遍历到的值一定是递增的。
2023-06-15 13:30:05
36
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人