自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(75)
  • 收藏
  • 关注

原创 柠檬水找零(力扣860)

这道题的贪心很简单,就是体现在对于20元的找零上。根据题意,20元有两种找零方式:1.找一张5元和一张10元;但是5元比较万能,因为无论是10还是20都需要用5元来找零,所以我们优先考虑第一种找零方式,这就是贪心所在。大家可以结合我下面的代码及注释理解此题。

2025-02-22 21:47:04 330

原创 分发糖果(力扣135)

题目说相邻的两个孩子中评分更高的孩子获得的糖果更多,表示我们既要考虑到跟左边的孩子比较,也要考虑右边的孩子,但是我们如果两边一起考虑一定会顾此失彼。这里就引入一个思想:先满足右边大于左边时的糖果分发情况,再满足左边大于右边时的糖果分发情况。需要注意的是,在满足后者的情况时,我们用到贪心的思想:取candyVec[i + 1] + 1 (满足后者情况时的糖果数量)和 candyVec[i] (满足前者情况时得到的糖果数量)中较大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。

2025-02-22 21:43:08 322

原创 加油站(力扣134)

既然每一个加油站都有对应的加油量和耗油量,我们不妨计算一下每个加油站的汽油净增量。如果每个加油站净增量之和不为负数,则说明一定可以找到唯一的起始点。那我们该如何找到这个起始点呢?我们设置最开始的起点为第0个加油站,接着通过for循环往后遍历每一个加油站,同时将每个加油站的净增量逐个累加。在这个过程中我们运用贪心思想:当汽油净增量之和为负数时,我们就可以将起始点更新到当前加油站的下一位。大家可以结合我下面的代码及详细注释理解此题。

2025-02-22 21:32:41 389

原创 跳跃游戏II(力扣45)

的基础上需要找到最小的跳跃次数。那么我们需要用一个变量来统计跳跃次数,而难点就在于何时让该变量的值增加。这一点我写在注释中,大家结合我的代码会更好理解。几乎相同,我就不再次赘述了。

2025-02-21 21:36:30 276

原创 跳跃游戏(力扣55)

题目问是否可以跳到数组最后一个下标,有的同学可能会思考如何模拟跳跃这个操作,但这是比较困难的,很容易把自己绕进去。可以换一种思路,我们不需要知道具体是如何跳到最后一个下标的,而是找到最大的跳跃范围。如果该跳跃范围可以覆盖最后一个下标,就说明我们一定可以通过某种跳跃策略到达最后一个下标。更具体来说,不一定非要明确一次究竟跳几步,而是每次取最大的跳跃步数,这个就是可以跳跃的覆盖范围。这个范围内,别管是怎么跳的,反正一定可以跳过来。为了实现这个想法,代码的书写上还是有一定的技巧性。

2025-02-21 21:10:41 547

原创 买卖股票的最佳时机II(力扣122)

这道题有两个注意点,一是我们永远都只能持有一支股票,二是一天之中只能在买股票和卖股票中二选一。第一次做这道题一般都是这样想,选一个价格低的一天买入,再选个价格高的一天卖,再选一个低的买入.....循环反复,但我们根本确定不了多高算高,多低算低。不妨换一种思考方式,举个例子:我们第一天买股票,第三天卖股票,期间获得的利润可以拆成第一天到第二天的利润与第二天到第三天的利润之和,也就是将一次买卖拆成多个交易单元。局部最优,也就是只有当交易单元利润为正才算入总利润,全局最优就是最后得到的利润是我们能获取的最大值。

2025-02-14 15:21:30 308

原创 最大子数组和(力扣53)

当我们发现当前的子数组和已经为负数时,就要立马清0,因为继续加的话,一定会让后面的数字变小,这样一定无法达到题目要求的最大子数组和。我们需要用变量将局部的子数组和存储起来,并且随着遍历的进行,每当我们求得更大的局部最大子数组和时就更新该变量,最终该变量的值就是最大子数组和。需要注意的是我们给存储子数组的和的变量初始化时一定是用INT_MIN,千万不要习惯性初始化为0,原因是: 如果输入用例都是-1,或者 都是负数,那么最大的子数组和一定是其中最大的负数。大家可以结合我下面的代码及注释理解此。

2025-02-12 23:30:25 164

原创 分发饼干(力扣455)

我们可以先将胃口和饼干的数组进行从小到大的排序,让小胃口的小孩吃到尽可能小的饼干,只有当一个小孩吃到了饼干才可以投喂下一个小孩。当所有饼干都遍历了一遍之后,我们就得到了最终分到饼干的小孩个数,这也是最大数。需要说明的是,每一道贪心都可以用数学方法严谨证明,但是没必要,很容易自己陷进去出不来,我们只要无法找到反例,就可以试试我们当前的贪心策略。这个算法没有固定的套路,甚至题目之间的联系也很少,基本上每一道题都要当新题来写。我们能做的只有见多识广,这样才有机会在考试中根据以往经验解决贪心的题目。

2025-02-12 23:10:40 479

原创 全排列II(力扣47)

的不同就在于集合中有相同元素,我们唯一多的操作就是在同一层递归中也要去重,其他的都与上一题相同。大家可以结合我下面的代码及详细注释理解此题。

2025-02-12 22:31:30 418

原创 全排列(力扣46)

这道题让我们求这个集合有多少种排列方式,那么与之前组合问题的不同就在于要考虑元素之间的顺序了,所以每一层递归的or循环的起始值无需变量控制,都从0开始。但是一个排列中不能出现相同元素,所以别忘了去重,这里的去重方法也是之前讲过的。设置一个数组,下标对应集合中元素的下标,数组值为0表示在当前排列中未使用过,1则表示使用过。另外,题目说了集合中的元素互不相同,所以这里的去重仅仅指的是一个排列中不出现相同元素,而不需要在同一层递归中去重。大家可以结合我下面的代码及详细注释理解此题。

2025-02-12 22:24:44 383

原创 非递减子序列(力扣491)

这道题的难点依旧是去重,但是与之前做过的子集类问题的区别就是,这里是求子序列,意味着我们不能先给数组中的元素排序。因为子序列中的元素的相对位置跟原数组中的相对位置是一样的,如果我们改变数组中元素的顺序,子序列也会发生改变。哈希表的使用我们之前也练过不少题,这里就不详细说明了,忘记的同学可以看一下之前的博客。需要注意的是,我们需要在每一层递归中都定义一个新的哈希表,原因在于:往下递归子序列可以取重复的元素,但是在同一层递归的for循环中遍历时需要跳过重复的元素。

2025-02-09 22:20:23 298

原创 子集II(力扣90)

的区别就在于集合中的元素会重复,那么还按照之前的代码来操作就会得到重复的子集,因此这道题的重点就在于去重。需要注意的是,这里的去重指的是在同一层递归中,而在往下递归的子集中可以取重复的元素。那么具体是如何实现的呢?其实用到的方法还是之前。这道题使用过的套路。额外注意的是,我们一定要先记得将集合排序,再使用这种去重方法。大家可以结合我下面的代码及详细注释理解此题。

2025-02-09 22:02:36 310

原创 子集(力扣78)

这道题与之前做过的回溯问题最大的区别就是,我们在每一层递归都可以得到一个结果,也就是题目中所说的子集,而之前的题是在终止条件才将结果存入二维数组。需要注意的是,每一层递归中将结果存入二维数组的代码段需要放在终止条件之前。否则最后的子集还没存入就退出递归了。其他的部分都是之前的模版,我就不解释了,大家可以结合我下面的代码及详细注释理解此题。

2025-02-09 21:49:04 356

原创 复原IP地址(力扣93)

有了上一道题分割字符串的基础,这道题理解起来就会容易很多。相同的思想我就不再赘述,在这里我就说明一下此题额外需要注意的点。首先是终止条件如何确定,上一题我们递归到超过字符串长度时,则说明字符串已经分割完毕,而这道题根据题意,相当与用‘.’来分割字符串,且出现三个点时就可以结束递归了,那么我们需要一个变量来记录点的个数。另外,在我们判断分割出来的子串是否合法时,最后出现的子串可能为空串,就是说第三个点之后没有数字了。这是一些注意的重点,其他细节比较好懂,大家可以结合我下面的代码及详细注释理解此题。

2025-02-08 21:28:57 285

原创 分割回文串(力扣131)

这道题咋一看与之前做过的组合问题不相干,实际上仍然需要用上组合问题的模版。分割操作其实就是组合问题里的递归子集并挑选数字。举个例子:我们有一个字符串1,2,3,4,组合问题中我们先在最开始的集合中选择1,然后递归子集2,3,4,这一步其实就可以模拟分割。我们挑选1,可以理解为在1的后面划了一条分割线,然后继续分割2,3,4。分割过程中,子串的获取可以借助substr这个库函数。这是大致思路,大家可以结合我下面的代码及详细注释理解此题。

2025-02-08 21:12:13 267

原创 组合总和II(力扣40)

这道题的难点就在于题目所给的集合中有重复的数字,我们需要进行去重操作。注意并不是对递归的集合去重,而是对当前集合的遍历进行去重。这么说可能有点抽象,举个例子:假设集合为1,1,2,3,4,我们第一次选1,递归集合时,我们仍可以选择第二个1。不过,我们需要判断这个重复出现的数字是在当前这层递归的for循环中还是在下一层递归的for循环中。于是,我们创建了一个数组,标识这些集合中的数字是否被使用过,如果被使用过,说明是在上一层递归中被使用,如果没有被使用,说明是在当前这一层递归的for循环中。

2025-02-07 21:44:55 282

原创 组合总和(力扣39)

这道题又在之前的基础上进行了变形。递归是在一个集合里进行,但每次递归我们可以选择重复的数字,这代表递归时不需要缩小集合范围。但是组合的无序性仍要考虑,所以每一层for循环的起始值还是需要用变量控制。另外,我们可以事先对元素排个序,因为此题需要求和并与目标值进行比较。通过排序,我们就可以进行剪枝操作,提高效率。大家可以结合我下面的代码及详细注释理解。

2025-02-07 20:29:09 246

原创 电话号码的字母组合(力扣17)

一是根据题目所给的键盘布局进行数字到英文字符串的映射,这一步可以用二维数组实现。二是这道题在递归的时候不需要缩小范围,这与之前写的组合题目有所不同。此题并不是在一个集合中不断递归遍历,而是递归另一个集合。所以不需要考虑递归时集合大小的改变。大家可以结合下面的代码及详细注释理解此题。

2025-02-07 20:05:00 225

原创 组合总和III(力扣216)

大差不差,主要讲解一下剪枝(下面的代码也有回溯操作的详细注释)。我们可以发现,如果我们递归到后面,可能集合过小,无法满足题目要求的k个数的组合,为了保证我们一定可以找到k个数的组合,在for循环中遍历当前集合时,要控制选取元素的边界在哪。就是说我们不能选到集合中太靠后的元素,这会导致递归的子集过小,无法选出k个数的组合。另外,当我们选出来的数字已经大于目标和时,可以直接退出递归,这也是一种剪枝。大家可以结合我下面的代码及注释理解此题。这道题在回溯的基础上加入了剪枝操作。回溯方面我就不过多赘述,与。

2025-02-06 21:12:05 691

原创 组合(力扣77)

毕竟回溯递归不分家,必须先有递归,才会有回溯。举个例子:最开始的集合有1,2,3,4,那么我们最开始一定是从这个集合中选一个数。接下来讲一下回溯,我们需要写一个for循环将递归函数包起来,这个for循环的作用是遍历当前集合的所有数,假设在第一个集合中我们已经选了1这个数,然后递归选择第二个数,那么在选择第二个数的递归函数结束之后,我们可以将1弹出存储组合的数组,并通过for循环选择第一个集合中的第二个数,这样就得到了其他组合情况。这道题大家可以当做模版题记下来,之后的回溯算法的代码风格都与这道题大差不差。

2025-02-06 15:07:53 1102

原创 将有序数组转换为二叉搜索树(力扣108)

这道题需要在递归的同时使用双指针。先找到一个区间的中间值,当作子树的父节点,再递归该中间值的左区间和右区间,用于生成该父节点的左子树和右子树。这就是此题的递归逻辑。而双指针就体现在每一层递归都要使用左指针和右指针来找到中间值。这里的双指针的移动逻辑与二分法中双指针的移动相同。所以我们也需要注意合法区间的选择。另外,这道题的递归函数的返回值为指向节点的指针,从而可以使用链表的连接操作将生成的父节点与上一层的父节点连接,最终构造成一棵树。大家可以结合我下面的代码及注释理解此题。

2025-02-06 00:17:17 296

原创 修剪二叉搜索树(力扣669)

这道题还是比较复杂,在递归上与之前写过的二叉树的题目都有所不同。如果当前递归到的子树的父节点不在范围中,我们根据节点数值的大小选择进行左递归还是右递归。因为该不满足要求的父节点的子树中可能存在满足要求的节点,我们要不断递归子树寻找这些满足要求的节点并向上返回,直到遇到空节点为止。注意这里递归函数的返回值为指向节点的指针,用来返回满足要求的节点。另外,递归到的子树的父节点满足要求时,需要进行链表的连接操作,刚好接住前面所说的满足要求的节点,最后再向上返回该节点,用于之后的连接。

2025-02-06 00:03:05 504

原创 二叉搜素树中的插入操作(力扣701)

为了满足题目的要求,我们可以选择在叶子节点之后添加节点,这样既可以满足题目要求,也不会破坏二叉搜索树的结构。在二叉搜索树中递归的时候,要根据大小,选择进行左递归还是右递归。当递归到空节点的时候,我们就可以添加节点了。同时,递归函数的返回值要用变量接收。这里的返回值为指针,我们采取链表的连接方式接收返回值,相当于将子树加入到该二叉搜索树中。这是大致思路,大家可以结合我下面的代码及注释理解此题。

2025-02-03 09:00:51 388

原创 二叉搜索树的最近公共祖先(力扣235)

根据题意,这是一棵二叉搜索树,那么我们遍历时可以利用其特点。如果当前遍历的节点大于p和q,那么只需要遍历该节点的左子树,反之遍历右子树。如果这个节点的数值介于p和q之间,那么该节点就是最近公共祖先。因为p和q在不同的子树,我们如果取别的节点为祖先,根本不可能连接p,q,只能是当前这个介于p,q之间的父节点。这只是大体思路,大家可以结合下面的代码及注释加以理解。

2025-01-27 22:12:12 130

原创 二叉树的最近公共祖先(力扣236)

根据题意,我们需要寻找的是节点p,q的公共祖先。需要看该节点的左右子树,如果左子树存在p或者q,右子树存在p或者q,那么该节点为公共祖先。但是题目还要求是最近的,这就必须要从二叉树的最底部开始判断。我们可以选择后序遍历。因为后序遍历的处理逻辑写在左递归和右递归之后,导致其拥有天然的回溯操作,这使得我们可以从最底部往根节点执行处理逻辑。另外,还有一种特殊情况,就是两个节点连接在一起,那么最近公共祖先就是先遍历到的那个节点。但是我们最开始讲的思路可以包括这种特殊情况,所以不需要做额外处理,我们心里有数就行。

2025-01-27 20:50:01 296

原创 二叉搜索树中的众数(力扣501)

为了方便计数,我们使用双指针法,一旦发现当前且节点和前一个节点相同(指的是按照中序遍历的顺序的前一个),则累加该数字的次数。其实有更巧妙的方法,我们不管三七二十一,一但遍历到新的数字且次数大于最大次数(注意这里的最大次数一开始就是为初始值,并不是真正的最大次数),就放入结果数组。随着遍历的进行我们该数字的次数会增加,当他大于最大次数时,就更新最大次数,同时将之前放在结果中的数字删去,放入新的数字(这个数字可能没有变,也可能变了)。这只是大致思路,大家可能不是很明白,可以结合我下面的代码以及注释理解。

2025-01-26 23:34:22 430

原创 验证二叉搜索树(力扣98)

根据二叉搜索树的特性,我们使用中序遍历,保证节点按从小到大的顺序遍历。既然要验证,就是看在中序遍历的条件下,各个节点的大小关系是否符合二叉搜索树的特性。双指针法和适合解决这个问题,一个指针指向当前节点,另一个指针指向前一个节点(指的是按照中序遍历顺序的前一个节点),不断后移两个指针,两两进行比较。这只是大致思路,大家可以结合我的代码以及注释加以理解。

2025-01-26 23:21:40 409

原创 二叉搜索树的最小绝对差(力扣530)

因为是二叉搜索树,那么我们一定使用中序遍历,这样可以保证按从小到大的顺序遍历节点数值。要求两个节点的最小绝对差,我们这里可以使用到双指针法,让一个指针指向当前遍历到的节点,另一个指针遍历前一个节点(这里的前一个节点指的是按照中序遍历的顺序的前一个节点)。每遍历到一个新的节点都可以更新一下最小的差值,差值用一个全局变量存储。根据这个思路,我们可以发现这个递归函数并不需要返回任何值,只需要遍历所有节点即可。大家可以结合我下面的代码及注释理解。

2025-01-26 23:03:56 155

原创 二叉搜索树中的搜索(力扣700)

首先介绍一下什么是二叉搜索树。

2025-01-25 23:36:35 471

原创 合并二叉树(力扣617)

这道题需要操控两棵二叉树,并且是“同步”遍历,如果两个二叉树的节点都不为空,就可以直接相加,这一步作为递归函数处理逻辑,如果有一方为空,就可以退出递归,这是递归终止条件。为了便于思考,我们采用前序遍历,也就是从根节点往下走,每遍历到一个节点执行处理逻辑。大家可以结合我下面的代码以及注释理解此题。

2025-01-25 22:40:50 353

原创 路径总和(力扣112)

题目给了我们目标路径和,我们可以每遍历一个节点就让路径和减去该节点的值,如果遍历到该条路径的叶子结点发现路径和刚好减为0,说明我们找到了满足要求的路径。那么我们的递归终止条件自然可以写成遍历到叶子节点,并且遍历到叶子节点就判断路径和是否为0。如果为0,就可以在每一层递归不断返回true,如果不为0,则需要回溯,进而递归其他的路径。这就是大致的思路,大家可以结合下面的代码以及注释理解这道题。

2025-01-25 17:23:18 351

原创 找树左下角的值

这道题最关键的点就是涉及回溯。为什么需要用回溯呢?因为记录深度的变量随着递归不断往下会越来越大,而当我们结束一层递归的时候需要得到未进行该层递归的深度大小(得到的大小用于继续递归,不过这次递归的方向会改变,也就是我们所说的左递归和右递归),那么我们通过回溯就可以实现这一目的。我们每次在递归的叶子节点时需要终止该层递归,并保存该叶子节点的值。等遍历到其他的叶子结点,如果该叶子结点更深,我们需要更新保存叶子节点值的变量(这一步操作也是终止环节的一部分)。这只是大体思路,大家可以结合我下面的代码以及注释理解。

2025-01-24 23:52:18 317

原创 完全二叉树的节点个数(力扣222)

这道题可以当成一般的二叉树直接遍历,但是我们如果利用完全二叉树的特点遍历,可以节省一些时间。完全二叉树只有两种情况,要么是满二叉树,要么有一部分子树是满二叉树。我们可以统计子树的左右两侧节点,来判断该子树是否是满二叉树(注意仅限于这道题可以这样判断,因为在整棵树为完全二叉树的前提下,子树如果为满二叉树,那么它的左右两侧节点的高度一定相同)。在写终止条件时,要计算以该父节点为根节点的子树的两侧节点高度,如果相同,则直接退出本层递归。这是本题大致思路,大家可以结合我下面的代码以及注释理解。

2025-01-24 23:27:07 390

原创 左叶子之和(力扣404)

这道题需要将左右子树的左叶子结点之和不断返回给该左右子树的父节点,这是典型的后序遍历。如果大家对于二叉树的遍历不熟悉的话,可以先去看一下我的关于二叉树遍历的博客。否则直接看这道题是很容易懵逼的。熟悉了二叉树的遍历之后,大家可以结合下面的代码以及注释理解这道题是如何处理的。

2025-01-23 23:29:37 398

原创 二叉树的所有路径(力扣257)

因为题目要求路径是从上到下的,所以最好采用前序遍历。这样可以保证按从上到下的顺序将节点的值存入一个路径数组中。另外,此题还有一个难点就是如何求得所有路径。为了解决这个问题,我们需要用到回溯。回溯和递归不分家,每递归一次,我们就回溯一次,这样就能保证回到原来的位置,进而递归我们没有走过的节点,得到新的路径。大体思路就是这样,大家可以结合我的代码以及注释理解这道题目。另外,如果大家的二叉树遍历还不熟悉的话,最好先去看一下我的关于二叉树遍历的博客,再来看这道题,否则肯定会比较懵逼。

2025-01-23 22:52:15 313

原创 平衡二叉树(力扣110)

在这道题中,我们返回左右子树的高度的时候,需要比较左右子树的高度,如果子树并不平衡,直接返回-1,并且只要有一个子树不平衡,那么这棵二叉树就是不平衡的,所以我们可以写if语句,一旦检测到左右子树有一个高度为-1,就不断向上返回-1,最终在根节点得到的返回值也为-1,这表示这整个二叉树不平衡。反之,我们返回以该父节点为根节点的子树的高度,最终得到这整个二叉树的高度,这就表示这棵二叉树是平衡的,因为一旦在递归中途但回了-1,最后都不会得到该二叉树的高度。而一个子树的高度,就是父节点的最大高度。

2025-01-23 18:28:36 397

原创 二叉树的最小深度(力扣111)

题目可以转换成求该二叉树的最小高度。我们需要将父节点的左右孩子中的较小高度加一后返回给父节点,这样可以得到父节点的最小高度。通过逐层递归,最终返回根节点的最小高度。但需要注意的是,如果父节点的左右孩子中有一个为NULL,那么直接取不为空的孩子的高度。如果还按照取较小高度的逻辑,得到的值根本不是高度。可以结合下面的代码注释,更容易理解。

2025-01-22 21:50:23 253

原创 二叉树的最大深度(力扣104)

要获取最大高度,我们需要将节点的左右孩子的高度的结果取较大的那个值返回给父节点。通过不断地调用递归函数返回左右孩子的较大高度,最终可以得到根节点的最大高度。这个操作就是典型的后序遍历。大家可以结合下面的代码与注释,很容易理解这个问题。所谓二叉树的最大深度其实也是根节点的最大高度。那么要解决这个问题,我们该选择哪一种遍历方式呢?

2025-01-22 21:03:04 341

原创 对称二叉树(力扣101)

这道题翻译过来就是判断根节点的左右子树是否可以通过翻转,变得完全一样。那么什么样的左右子树可以通过翻转相互变换呢?它们的节点的数值一定对称分布。那么我们就需要同时遍历左右树,不断比较左右子树的对称节点的数值是否相等。要实现这个思路,也要基于最基础的二叉树遍历。按照上面的思路,我们需要将对称节点的数值是否相等的判断结果返回给父节点。通过逐层的递归返回,我们最终可以得到根节点的左右子树的对称节点数值都相等。大家可以结合我下面的代码和注释理解。其实广度优先也可以,你们可以试试,这道题我就使用递归来做。

2025-01-22 20:41:21 434

原创 翻转二叉树(力扣226)

所谓翻转二叉树,就是将每一个节点的左孩子和右孩子交换(注意这里指的是指针交换,而不是交换节点的数值)。无非就是在遍历二叉树的基础上调用一下swap函数交换指针,跟遍历的代码几乎一样。但是我不推荐使用中序遍历,因为中序遍历会导致根节点的左子树的节点的左右孩子交换多次(可以动手画图模拟一下)。我直接写在代码注释中,大家结合代码很容易理解。这里我以前序遍历为例。

2025-01-22 18:30:03 296

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除