自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 算法训练营Day50 第九章 动态规划part11

这道题可以参考上一题来写,只要理解了上一道题,那么这道题就能很容易的写出来了。思考的过程中,考虑边界问题可能比较抽象,可以带入k=2这样的具体值来推导,这样就比较容易理解了。然后按照动态规划5部曲解题就好了,那么最后哪个状态才是利润最大的状态呢?其实,状态⑤就是利润最大的状态了,就是本题需要求解得到的结果。因为状态⑤是包含了状态③的!这道题可以在前一天题目的基础上来写,与只能买入卖出股票一次时相比,需要多考虑几个状态。当然,我们可以发现,状态①实际上是对递推公式没有影响的,也就不用考虑这个状态了。

2023-10-16 17:04:55 134

原创 算法训练营Day49 第九章 动态规划part10

第一次做这道题感觉就是双指针,当fast对应的值大于slow对应的值时,就记录下来,并比较是否是最大值;当不满足该条件时,slow直接赋值为fast当前的位置,继续进行遍历即可。一次for循环就能求解出结果了。当然也可以考虑使用动态规划的方法来求解,思路也很简单,一看代码就知道啦。这道题同样可以想到用贪心算法来做,和上一题思路基本一致,直接给出代码。121. 买卖股票的最佳时机。122. 买卖股票的最佳时机Ⅱ。

2023-10-11 19:03:44 154

原创 算法训练营day48 第九章 动态规划part9

这道题和上一题相比,多了一个限制条件,即:开头和结尾元素也是相邻的,不能同时选取。单层递归的逻辑在于,要获取偷这个节点时的最大价值,以及不偷这个节点时的最大价值。能够发现,每个节点的值是依赖于它的两个子节点,所以应该采取后序遍历的方法,从下往上遍历,这样才能满足我们的需求。该递归函数参数为二叉树的节点,返回值为一个大小为2的vector<int>数组,数组的首个元素表示不偷这个节点时获取到的最大价值,尾部元素表示偷这个节点时获取到的最大价值;对后两种情况,分别用第一题的思路来解决就ok了。

2023-10-11 14:58:03 150

原创 算法训练营Day46 第九章 动态规划part8

其实,多重背包可以转化为01背包问题来解决,比如说:有3个物品A(重量为1,价值为2),2个物品B(重量为3,价值为5),转化后,就相当于有五个物品,对应的重量分别是{1,1,1,3,3},对应的价值分别是{2,2,2,5,5}。(2)递推公式的确定思路如下:可以截取一段字符串(假设字符串的范围是[begin, end]),那么如果s.substr(begin, end - begin + 1)存在于给定的单词中时,再判断dp[begin]是否为true,若是,那么就令dp[end]为true。

2023-10-10 21:20:57 110

原创 算法训练营Day45 第九章 动态规划part7

除了dp[0]根据题意应当初始化为0,其余应初始化为INT_MAX,如果初始化为0,那么接下来的推导就全是0了,这是需要注意到的!这道题需要注意的细节如下:因为是要求最少个数,递推公式为:dp[j] = min(dp[j], dp[j - coins[i]] + 1);改为:一步可以走一个台阶,两个台阶,三个台阶,.......,直到 m个台阶(一次可以走[1,m]这个区间内的数字的台阶)。那么这道题就转化为完全背包问题了,目的地的楼梯数相当于背包容量,[1,m]相当于物品。第二题 322. 零钱兑换。

2023-10-09 14:32:57 190

原创 算法训练营Day44 第九章 动态规划part6

今天学习了完全背包相关知识,可以发现,对排列和组合不同要求的题目,遍历顺序极其关键。Day44打卡!

2023-10-07 21:18:49 89

原创 算法训练营Day43 第九章 动态规划 part5

494. 目标和第一题: 1049. 最后一块石头的重量 II这道题的思路是:将这组石头分成大小相近的两组,两组石头之差就是本题结果了。然后,就可以把这道题变成一道01背包问题,背包的容量就是本组石头总重量的一半(向下取整)。可以理解为,重量与价值是相同的,找出这个背包能放入石头最大价值。

2023-09-15 16:51:30 84

原创 算法训练营Day42 第九章 动态规划part4

因为,如果从前向后遍历的话,会重复添加,在二维数组中,每一个dp数组的值的推导,要么取决于上方的元素,要么取决于左上方的元素,压缩成一维数组后,同样如此,要么还是本身,要么就是左侧元素推导来的,从前向后遍历,导致左侧元素被覆盖了,自然就有可能出现错误!dp数组第一行中,当能装的下编号为0的背包时,就初始化为value[0],否则应当为0;①确定dp数组的下标及含义:对于dp[i][j],其表示从编号小于等于i的物品中选取,在背包容量为j的情况下,能存放的物品的最大价值;练习题: 416. 分割等和子集。

2023-09-11 11:51:30 83

原创 算法训练营Day35 第八章 贪心算法 part4

比较规则如下:当前数组的第一个元素大于前一个数组的后面一个元素时,说明需要多加一支箭了;这道题凭借常识基本就能解决,需要注意的点就是:当顾客付的钱是20元时,我们优先给对方10元,再给一张5元,尽可能把5元留在手上。这道题和之前那道分发糖果的题目类似,不能同时考虑两边,需要先考虑一个条件,再考虑另一个条件,不然会顾此失彼,无法得到正确结果。②对于排序好的数组,从前向后插入到新的数组中,插入位置就是k的值(可以考虑使用list,因为vector的插入效率较低)。第三题: 452. 用最少数量的箭引爆气球。

2023-09-04 18:16:41 78

原创 算法夏令营Day34 第八章 贪心算法 part3

1005.K次取反后最大化的数组和。

2023-09-04 01:35:42 77

原创 算法训练营Day32 第八章 贪心算法 part2

这道题可以用贪心的方法来解决问题。我的想法是每次从最低点买入,从最高点卖出赚的钱是最多的。这样每次记录一个极大值与极小值的差,加到result中,最后result就是我们要求的结果了。

2023-09-02 19:23:18 53

原创 算法训练营Day31 第八章 贪心算法 part1

这道题可以使用贪心的方法来做,但是比较复杂了,需要考虑的情况比较多,可能不容易想全。如果不相同,再进行接下来的判断,用一个flag变量记录之前的差值是正数还是负数,初始化为0,第一次比较的时候,为flag赋值为nums[i] - prev即可;当flag为正数,说明上一次是递增的,这一次判断需要是递减的才能计数,如果这次还是递增的,那么我们移动指针向后,并且将本次的值赋给prev变量;这就是贪心算法的本质,贪心算法很难总结出相应的解题模板,需要凭感觉来进行贪心的过程,只要举不出反例,就可以尝试使用贪心法!

2023-09-01 12:58:20 183

原创 算法训练营Day28 第七章 回溯算法part4

这道题是求子集的问题,求子集问题与之前做过的求组合、分割问题相比,他是每一个节点的结果都需要收集起来,而组合or分割问题只需要收集叶子节点的结果。这道题跟前两天遇到的一道组合类的题目有些相似,也是需要使用到vector<bool> used这样一个数组来标记树层的前一个节点是否被使用过,其余方法和上一题类似,子集问题需要在每一个节点获取path并插入到result中。这道题还是一道分割类的题目,与昨天的最后一题比较相似,但是细节比较多,稍不留神就容易出错哇!第三题: 90.子集II。第二题: 78.子集。

2023-08-31 17:57:25 99

原创 算法训练营Day27 第七章 回溯算法part3

这道题与上一道题的区别在于,这道题中每个数字只能使用一次,而且可能存在数字重复的现象,比如数组为[1,1,1,1,1,1],target为3,所以需要进行去重操作。这道题和一开始学习回溯算法时遇到的那两道组合题目十分相似,不同点就在于,因为这道题允许重复选取元素,因此对于index的设置有所差别,下一次回溯时,传入的index可以是本次遍历时的i,而不用i+1。与之前做的组合类型的题目相比,不同的地方在于,分割问题每次分割一个区间的内容插入path,而组合问题一次选择一个值插入path中。

2023-08-30 19:29:38 112

原创 算法训练营Day25 第七章 回溯算法part2

还有一个剪枝的操作,与上一题是类似的,当剩余需要插入path的数字不足以满足k的需求时,那就直接return吧,因为这个结果中的个数最后无法达到k个了,因此剪枝就好了。将当前遍历的字符串中的第i个元素放入path中,接着递归地调用回溯函数,传入的index需要加1,之后还需要回溯操作,弹出最后一个元素。③确定单层搜索过程:单层搜索的过程与之前那道题类似,只不过每次将一个数字放入path的同时,还需要将这个数加给sum,而且在回溯的时候,不仅要pop尾部元素,也需要从sum中减去相应的数字。

2023-08-29 17:29:20 100

原创 算法训练营Day24 第七章 回溯算法part1

确定单层搜索的过程,for循环用来横向遍历,递归则用来纵向遍历,如下图所示。

2023-08-29 13:46:28 107

原创 算法训练营Day23 第六章 二叉树part9

当root->val < low的时候,该节点以及该节点左子树上的值都不在区间内,而右子树上的值仍有可能在区间内,因此继续遍历右子树上的节点,并返回,上一层递归函数会接收到返回值;同理当root->val > high时,该节点以及右子树上的值都不在区间内,左子树上的值有可能在区间内,因此去遍历左子树上的节点,并返回结果。的顺序来遍历整颗二叉搜索树,这种方法能够很好的利用二叉搜素树的特性,即:每次遍历时得到的都是未遍历过的节点中的最大值,再设置一个。求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。

2023-08-27 23:24:42 104

原创 算法训练营Day22 第六章 二叉树part8

情况⑤稍微复杂一些,我们可以考虑让右孩子来替代被删除的节点,同时再让左子树的部分成为右子树中最左侧的节点的左子树。②要删除的节点为叶子节点;④要删除的节点左孩子不为空,右孩子为空;这道题同样应该想到运用二叉搜索树的特性来解题,并且可以发现,在叶子节点插入节点就可以满足题意。当插入值小于当前比较节点的值时,就向当前节点的左子树一侧遍历,反之则向右子树一侧遍历。这道题与昨天的最后一题比较相似,但相比于上一题,这道题可以利用二叉搜索树的特性(左子树上的值都比该节点的小,右子树上的值都比该节点的大)。

2023-08-26 23:10:12 104

原创 算法训练营Day21 第六章 二叉树part7

还可以在此基础上进行简化,同样需要采用后序遍历的方法,因为后序遍历是天然的回溯方法,通过回溯法来记录最近的公共祖先,可以从下到上来判断一棵树。这道题可以使用递归法也可以使用迭代法,用双指针操作能够降低空间复杂度。这道题同样可以采用双指针的思路进行解题,并且看到二叉搜索树就要立马想到它的。第一题: 530.二叉搜索树的最小绝对差。第三题: 236. 二叉树的最近公共祖先。第二题: 501.二叉搜索树中的众数。

2023-08-25 17:28:29 110 1

原创 算法训练营Day20 第六章 二叉树 part6

这道题和前一天的最后一题比较类似,都是构造二叉树的题目。只要按照类似的方式进行递归就可以了,注意一下边界条件就ok。这道题比较容易想到递归法,只要确定了递归终止条件,并且明确单层递归的逻辑,这道题就能够很好地解决啦!要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。第三题: 700.二叉搜索树中的搜索。第四题: 98.验证二叉搜索树。第一题: 654.最大二叉树。第二题: 617.合并二叉树。例如要搜索元素为3的节点,

2023-08-19 01:15:54 122

原创 算法训练营Day18 第六章 二叉树 part5

这道题用迭代法比较简单,通过层序遍历很容易就能解决这道题目,我们只需要记录最后一行的最左侧元素即可,可以通过一个变量记录每一行的第一个元素,每次循环时对这个变量进行覆盖即可,最后跳出循环的时候这个变量就记录的就是最后一行的最左侧元素;或者在层序遍历时,每次都让right节点先进入队列,这样最后一个出队列的就是最后一行的最左侧元素了!④根据中间节点分割中序数组,前半部分为中序左数组,后半部分为中序右数组;⑤根据中序数组的分割结果,来分割后续数组,得到后序左数组和后序右数组;③确定单层递归的逻辑;

2023-08-17 23:35:56 128 1

原创 算法训练营Day17 第六章 二叉树part4

这道题采用递归法比较简单,使用的方法是前序遍历(中左右),先比较中间节点,不符合条件就返回false,然后依次比较左右两个节点,不符合也返回false。的节点,使用递归法解题很简单,按照递归三部曲:①判断函数的参数和返回值;③写出单次递归的逻辑。这道题要注意左叶子的定义,左叶子是指一个是其。第二题: 257. 二叉树的所有路径 (优先掌握递归)第一题: 110.平衡二叉树 (优先掌握递归)第三题: 404.左叶子之和 (优先掌握递归)

2023-08-16 16:58:42 117 1

原创 算法训练营Day16 第六章 二叉树part3

这道题同样可以采用递归和迭代两种方法来解决,如果没有考虑到完全二叉树的特性,只把这道题当作普通二叉树来求解,那么递归法和迭代法(层序遍历法)都需要遍历到每一个节点,时间复杂度为O(n)。也就是说,其实可以发现,满二叉树的节点数量为。对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。对于完全二叉树而言只有两种情况:情况一是满二叉树,情况二是最后一层叶子节点没有满。对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。

2023-08-11 23:22:42 148 1

原创 算法训练营Day15 第六章 二叉树 part2

层序遍历这种类型的题目有类似的解法,可以利用队列这种数据结构进行解答,因为队列具有。准确的来说是一个树的遍历顺序是左右中,另一个树的遍历顺序是右左中。这道题可以采用递归解法,也可以采用迭代的解法,这道题可以用递归的方法解决,并且需要使用。第三题: 101. 对称二叉树 (优先掌握递归)的特点,可以利用这一特性将每一层的数据一起遍历。第二题: 226.翻转二叉树 (优先掌握递归)

2023-08-11 15:09:30 186 1

原创 算法训练营Day14 第六章 二叉树part1

Ⅳ、平衡二叉搜索树:又称为AVL(Adelson-Velsky and Landis)树,具有以下性质:它是 ⼀棵空树或它的左右两个子树的⾼度差的绝对值不超过1,并且左右两个子树都是⼀棵平衡⼆叉树。迭代法需要通过stack这种数据结构来完成,前序遍历(中左右)和后序遍历(左右中)的写法比较接近,后序遍历可以在前序遍历的基础上稍作修改来完成,而中序遍历写法与上述两者有一定差异。Ⅰ、满二叉树:如果⼀棵⼆叉树只有度为0的结点和度为2的结点,并且度为0的结点在同⼀层 上,则这棵⼆叉树为满⼆叉树。

2023-08-09 01:04:25 123

原创 算法训练营Day13 第五章 栈与队列part03

想到这里,我们就可以让队列的front为最大的那个数字。执行push操作时,当要放入数组中的元素比队列的back大时,我们就重复执行pop_back操作,直到要放入的数字不再大于back元素;执行pop操作时,若队列的front元素等于理应该pop的数字时,我们再执行pop,否则我们就不应该pop,这时说明在push操作时,对应的数字已经被pop出去了。这道题需要用到哈希表以及优先队列,并且用到的优先队列应当为小堆序,这样我们只需要维护一个大小为k的优先队列即可,并且时间复杂度为O(n * logk)。

2023-08-08 20:54:35 121

原创 算法训练营Day11 第五章 栈与队列part2

因为stack帮助我们记录了遍历数组当前元素时候,前一个元素是什么,因此stack适合解决这种“爱消除”类的问题。这道题最后需要反转一下字符串,因为stack取出来的字符是反着的。去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。再进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么。逆波兰表达式指的是一种后缀表达式,所谓后缀就是指运算符写在后面。这道题也可以利用stack来解决,只不过本题不要相邻元素做消除了,而是做运算!

2023-08-06 16:31:06 105

原创 算法训练营Day10 第五章 栈与队列part1

HP STL 其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,而且开放源代码。这道题要求使用队列去实现栈,与上一题不同,我们用一个队列就可以模拟栈了,要掌握使用一个队列实现栈的方法哦!这道题可以用模拟法来解决,不涉及复杂的算法,只要对栈和队列这两种数据结构比较熟悉即可,需要两个栈去实现一个队列,其中一个为。首先,我么需要知道,C++标准库有多个版本,要知道我们使用的STL是哪个版本,才能知道对应的栈和队列的实现原理。

2023-08-06 15:01:40 87

原创 算法训练营Day9 第四章 字符串part2

第一部分:KMP算法总结与归纳KMP算法用于解决在一段较长的字符串中找出是否存在与另一个较短字符串相同的子串,举个例子:有字符串haystack = "sadbutsad"和字符串needle = "sad",我们找一下在前一个字符串中,是否存在与后一个字符串相同的子串,这时如果使用暴力解法,时间复杂度为两者大小之积,比较耗费时间,可以使用KMP算法来更好地求解这一问题。KMP算法的优势在于对于较长字符串haystack而言,遍历的过程中一直是从前向后的,不会出现往前移动重复查找的问题。

2023-08-05 22:34:21 41 1

原创 算法训练营Day8 第四章 字符串part1

看了题解之后,发现还可以不申请额外空间,在原先传入的字符串上操作就能解决这道题目,空间复杂度就从第一种方法的O(n)降低到了O(1).这道题很容易能想到重新创建一个空的string,然后按题目要求遍历s并添加到这个新建的string中就能得到答案。比较简单的一道题,双指针法就可以解决问题,分别交换两个指针指向的内容即可,通过这道题可以较好地理解双指针法。关键其实在于精简代码逻辑,可以写出如下代码,每次令i移动2k个位置进行判断就OK。用模拟法就能解决这道题,根据题目中的要求很容易写出代码,本道题目的。

2023-08-03 20:58:32 46

原创 算法训练营Day6 第三章 哈希表part1

这道题是典型的使用unordered_map的题目,我们创建一个unordered_map,令其first为数组元素,second为数组下标,然后遍历数组,找寻map中是否存在(target - nums[i]),找到了就返回此时的下标和对应迭代器的second组成的数组。①数组法:因为数字在[0, 1000]中,所以可以先设计一个大小为1001的数组来存放nums1中哪些数字出现过,出现过的数字置为1,没有出现的数字初始化为0即可,然后遍历nums2数组,将相交的元素放入结果集中,并将该位置置为0。

2023-08-01 20:29:25 45

原创 算法训练营Day7 第三章 哈希表part2

第一题: 454.四数相加II第一次写这道题的时候,没有想到其他思路,就用了暴力解法,相当于三层for循环,再加上while的寻找过程,算法的时间复杂度为O(),导致代码运行时直接报错,超时了!看了题解后,发现巧妙的解法,将时间复杂度能够降到O(该解法思路如下:首先我们将前两个数组中的元素之和以及这个和的出现次数存放到一个unordered_map<int, int> mp中,first表示数组A和数组B中任意两个元素之和(a+b),second表示(a+b)一共出现了多少次。

2023-08-01 19:53:14 42 1

原创 算法训练营 Day4 链表part2

循环条件同样为存在两个元素时,第一步先让cur的next指向第2个元素,第二部让第2个元素的next指向第一个元素,第三步是让第1个元素的next指向原先链表中位于第二个元素之后的那个元素,最后移动cur指针,即:cur = cur->next->next,这样就完成了一个循环。在循环中需要进行判断,后面是否还有两个元素,如果有两个元素存在的话,本次操作中的首元素的next应该指向后面一组元素中的后一个(例如:1->2->3->4,对1和2操作时,让2先指向1,再让1指向4);

2023-07-29 20:55:56 116

原创 算法训练营Day3 链表part1

①链表是通过指针串联在一起的线性结构,包括数据域和指针域两个部分。常见的链表类型有:单向链表、双向链表以及环形链表。②与数组的区别:数组在内存中是连续的,而链表则是非连续的,链表通过指针域的指针连接在内存中的各个节点。第一遍做没思路,链表对象中如何放入结点并保存?用什么数据结构来完成呢?

2023-07-28 20:01:01 65 1

原创 算法训练营Day2 数组part2

②双指针解法:数组中有负数,所以平方后最大的数字可能出现在数组的左右两侧位置,且左右两侧数字的平方一定大于中间数字的平方。因此,我们可以设置两个指针left和right分别指向数组的首尾两侧,比较平方后较大的数字,插入新数组的末尾,然后移动指针继续比较,直到将原先数组的平方全部放入新数组中为止。是一种更加通用的解法,能够解决m*n这种一般矩阵的问题,不必非得是n*n矩阵。②滑动窗口法:一次for循环解决问题,只需对滑动窗口的右边界进行for循环,左边界则动态的更新,时间复杂度为O(n)。

2023-07-27 23:45:09 157 1

空空如也

空空如也

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

TA关注的人

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