- 博客(33)
- 收藏
- 关注
原创 用ACM模式模板刷hot100
把while内容删除(一般刷hot100题目输入不需要同时输入几组)自己再写一个方法,就是力扣里的核心代码(加上static)第一个处理输入输出的方法里面调用第二块的方法。第二块完整写力扣代码,第一段先实例化再调用。这个方法可以不用,记第一个就行。第一个方法里写处理输入输出。给的模板一般是下面这样。
2025-03-23 13:56:04
780
原创 代码随想录算法训练营第四十一天 | hot65/100| 33.搜索旋转排序数组、153.寻找旋转排序数组中的最小值、155.最小栈、394.字符串解码
将数组一分为二,其中一定有一个是有序的,每次判断前半部分是有序的还是后半部分是有序的,每次只在有序的那部分里找。旋转后的数组一定被分成了前后两部分且两半都是升序数组,且前一半的最小值一定大于后一半的最大值,**只要用二分找到后一半的第一个元素即可**当一个元素要入栈时,我们取当前辅助栈的栈顶存储的最小值,与当前元素比较得出最小值,将这个最小值插入辅助栈中;有小于等于/大于等于的情况是因为,如果出现[2, 1]中找1的情况,需要有等于。在任意一个时刻,栈内元素的最小值就存储在辅助栈的栈顶元素中。
2025-01-25 00:14:56
407
原创 代码随想录算法训练营第三十九天 | hot61/100| 79.单词搜索、35.搜索插入位置、74.搜索二维矩阵、34.在排序数组中查找元素的第一个和最后一个位置
和二分查找一样,就是二分查找写两次,一次找第一个,一次找最后一个区别是多两个语句right--;// 重点else {// 初始化不能忘left = 0;last = mid;left++;// 重点else {两句重点right--和left++,是为了:比如找到第一个之后,right--,就意味着往左继续找,直到找到最左边的为止。
2025-01-22 18:48:45
268
原创 代码随想录算法训练营第三十八天 | hot57/100| 114.二叉树展开为链表、437.路径总和III、124.二叉树中的最大路径和、22.括号生成
假设当前的节点 p 的值为 val,我们对左子树和右子树进行递归搜索,对节点 p 的左孩子节点 p 求出 rootSum(p ,targetSum−val)而不是return maxSum?某个节点最大贡献值 = 该节点值 + 递归左节点最大贡献值 + 递归右节点最大贡献值。节点 20 的最大贡献值等于 20+max(15,7)=35,节点 −10 的最大贡献值等于 −10+max(9,35)=25。当 n = 3,应该生成 ()()(), (())(), ()(()), (()()), ((()))。
2025-01-16 13:44:36
973
原创 代码随想录算法训练营第三十七天 | hot53/100| 148.排序链表、543.二叉树的直径、230.二叉搜索树中第K小的元素、199.二叉树的右视图
寻找链表的中点可以使用快慢指针的做法,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。正确的是放在判断k==0后,这样的话假如pop完,k为0,那就正好是POP的这个 假如pop完,k为1,那就再遍历一个right,然后k-1,等于0,结束,就是这个right。放在判断k==0前,那么每次弹出一个,再遍历一个,就相当于遍历两个才k-1。用队列是因为后进后出,最后的节点是最后出的,也就是执行弹出操作次数到size-1时,弹出的就是最右边的。
2025-01-15 16:19:55
998
原创 代码随想录算法训练营第三十六天 | hot49/100| 21.合并两个有序链表、2.两数相加、25.K个一组翻转链表、138.随机链表的复制
第一次调用 reverseKGroup 时,会对 1 -> 2 -> 3 进行翻转,变成 3 -> 2 -> 1 -> 4 -> 5 -> 6 -> 7 -> 8。最后返回的时候,返回虚拟头.next,是避免头节点在操作过程中位置换了,而返回虚拟头.next,无论如何都可以。在头节点前设置一个节点,是为了避免处理边界情况复杂,设一个在前面的节点,后面就不用考虑是不是头节点而分类讨论。例如,假设链表为 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8,k = 3。
2025-01-14 16:30:38
348
原创 代码随想录算法训练营第三十五天 | hot45/100| 240.搜索二维矩阵II、160.相交链表、234.回文链表、141.环形链表
(2)如果 matrix[x,y]>target,由于每一列的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 y 列的元素都是严格大于 target 的,因此我们可以将它们全部忽略,即将 y 减少 1;(3)如果 matrix[x,y]<target,由于每一行的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 x 行的元素都是严格小于 target 的,因此我们可以将它们全部忽略,即将 x 增加 1。(2)然后遍历链表 headB,对于遍历到的每个节点,判断该节点是否在哈希集合中。
2025-01-09 13:44:20
430
原创 代码随想录算法训练营第三十四天 | hot41/100| 41.缺失的第一个正数、73.矩阵置零、54.螺旋矩阵、48.旋转图像
思路是自己搞一个哈希表,把 1 这个数放到下标为 0 的位置, 2 这个数放到下标为 1 的位置,按照这种思路整理一遍数组。然后我们再遍历一次数组,第 1 个遇到的它的值不等于下标的那个数,就是我们要找的缺失的第一个正数。当matrix是二维数组时,matrix.length表示二维数组的长度,也就是里面包含几个数组,也就是**行数**u、d分别是顶部和底部指针,l、r是左部和右部指针,i往一个方向行走时会和固定的某个指针合作,合作完就收缩圈子。对于矩阵中的第一行而言,在旋转后,它出现在倒数第一列的位置。
2025-01-08 17:58:45
384
原创 代码随想录算法训练营第三十二天 | hot37/100| 5.最大子数组和、56.合并区间、189.轮转数组、238.除自身以外数组的乘积
遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。新建一个数组nums_new,遍历原来的数组nums,原数组num[i]放在新数组nums_bew[(i + k) % nums.length]R[0]是1,R[i] = R[i +1]*nums[i + 1](2)L[0]是1,L[i] = L[i - 1] * nums[i - 1]
2025-01-08 17:52:29
767
原创 代码随想录算法训练营第三十一天 | hot33/100| 3.无重复字符的最长字串、438.找到字符串中所有字母异位词、560.和为K的子数组、239.滑动窗口的最大值
条件 pq.peek()[1]<=i-k 的含义就是判断优先队列队首元素所对应的原数组中的索引是否小于等于当前滑动窗口的左边界索引,如果满足这个条件,就意味着队首元素所代表的数据已经不在当前的滑动窗口范围之内了,需要将其从优先队列中移除。因为可能会有比如ww这种连续重复的,不能删一个就算了,要一直删,删到原来的字串里没有和这个新要添加的元素重复的为止。碰到重复的时,就递增子串的起始位置,同时子串的结束位置也是递增的(枚举新元素)背下来,不是arrays,不是Array,不是equal()
2025-01-06 22:45:00
200
原创 代码随想录算法训练营第三十天 | hot30/100| 49.字母异位词分组、128.最长连续序列、283.移动零、11.盛最多水的容器、42.接雨水
意思是获取key对应的值,如果存在,就是这个值,如果不存在,就获取一个空字符串。互为字母异位词的两个字符串包含的字母相同,因此对两个字符串分别进行排序之后得到的字符串一定是相同的,故可以将排序之后的字符串作为哈希表的键。* 从可能的起点开始,不断检查下一个连续的整数是否在集合中,如果在,则继续延伸连续序列,同时记录连续序列的长度。往map里添加键值(遍历每个字符串,排好序后作为key,原本的字符串作为值,键值添加到map里)* 首先,将数组中的所有整数存入哈希集合中,同时去除重复的整数。
2025-01-04 23:05:31
408
原创 代码随想录算法训练营第二十九天 | 贪心算法part03| 134.加油站、135.分发糖果
i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1。如果到i位置 和为负,能不能在[0,i]某一处,往后和为正,只是往前为负,把前面这段去掉就行。
2024-12-30 17:00:15
185
原创 代码随想录算法训练营第二十八天 | 贪心算法part02| 122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II、1005.K次取反后最大化的数组和
相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。把数组按从小到大排列,然后遍历,找到负的就取反,同时k--。如果遍历完之后,k还大于0,就进行以下操作:判断k是否大于0且是奇数(如果是偶数,就直接取反再取反,对结果没有影响),如果是,就对第一个数取反。如果遍历完之后,k还大于0,就进行以下操作:判断k是否大于0且是奇数(如果是偶数,就直接取反再取反,对结果没有影响),如果是,就对最后一个数取反。
2024-12-29 18:38:16
396
原创 代码随想录算法训练营第二十七天 | 贪心算法part01| 455.分发饼干、376. 摆动序列、53. 最大子序和
遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。用一个 index 来控制饼干数组的遍历,遍历饼干并没有再起一个 for 循环,而是采用自增的方式,这也是常用的技巧。大于0就让d=1,小于0就让d=-1。
2024-12-26 11:20:05
336
原创 代码随想录算法训练营第二十五天 | 回溯算法part04| 491.递增子序列、46.全排列、47.全排列 II
由于排列问题没有startIndex控制,每次都从0开始,used去重后,要判断if(used[i] == false),再进行处理。而不是[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]在组合总和II问题中,不需要判断if(used[i] == false),因为递归自动让startIndex递增,跳过重复的。输出就会是[[4,6],[4,7],[6,7],[7,7]]但是需要used数组,因为题干的数组有重复元素,不能重复用。
2024-12-25 11:16:30
304
原创 代码随想录算法训练营第二十四天 | 回溯算法part03| 93.复原IP地址、78.子集、90.子集II
只需要新建result,不需要新建path,因为结果是["255.255.11.135","255.255.111.35"]形式,一维数组,符合条件直接添加进去。终止条件和131.分割回文串就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。子集问题是所有树节点都添加,集合问题是符合长度的添加。s.substring(i, j+1)是返回字符串 s 的 i-j 位置的内容。
2024-12-25 10:50:16
325
原创 代码随想录算法训练营第二十三天 | 回溯算法part02| 39. 组合总和、40.组合总和II、131.分割回文串
这道题和前面组合问题的区别是,取的元素可以重复,也就是遍历的时候,同一个元素可以一直取。为了能用树层去重,判断candidates[i] == candidates[i - 1],提前要将重复的数字都放到一起,所以先进行排序。注意切割过的位置,不能重复切割,所以,backtracking(s, i + 1);注意切割过的位置,不能重复切割,所以,backtracking(s, i + 1);递归的时候,每次startIndex都从i开始,不从i+1,这样同一个数字就可以重复。
2024-12-24 12:48:19
886
原创 代码随想录算法训练营第二十二天 | 回溯算法part01| 77. 组合、216.组合总和III、17.电话号码的字母组合
String是不可变的,StringBuilder是可变的,允许在原地修改,提高了性能。新建字符串String[] numString = { 列举 } 或者String str = new String.....因为digits.charAt(num)是字母,要转成数字来表示位置,就要写成digits.charAt(num) - ‘0’StringBuilder有.append() .deleteCharAt()等方法。模板中,回溯撤销处理结果,之前在什么参数上添加,就在什么参数上撤销。
2024-12-22 19:57:29
371
原创 代码随想录算法训练营第二十一天 | 二叉树part08| 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树
如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。最后返回root节点。如图,比如节点0不符合区间要求,那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了(就是把节点0从二叉树中移除)从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了。而第二种写法,每次递归调用时,sum会先被初始化为0。
2024-12-17 14:13:25
236
原创 代码随想录算法训练营第二十天 | 二叉树part07|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点
第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。思路是:从上往下一直搜索,由于搜索树是有顺序的,如果要添加的值大于此时root的值,就往右搜索;第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点。第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点。第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点。
2024-12-16 14:56:41
334
原创 代码随想录算法训练营第十八天 | 二叉树part06|530.二叉搜索树的最小绝对差 、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先
(3).getOrDefault(A, B)是获取指定 key A对应对 value,如果找不到 key ,则返回设置的默认值B。对于一个节点,如果p在它的左子树,q在它的右子树,这个节点就是它们的公共祖先。或者p是q的节点、q是p的节点,p/q就是公共祖先。定义方法,递归遍历二叉树,把元素放到map里,键为root.val,值为出现次数递增,并更新最大次数。调用方法,找值为最大次数的数,把数放到动态数组里(普通数组不能动态添加元素)根节点是p/q,返回p/q。要用map,因为要索引,统计出现次数。
2024-12-15 20:34:02
215
原创 代码随想录算法训练营第十七天 | 二叉树part05| 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
这道题的解题过程和题目描述一模一样,按题干写就可以。代码如下(比代码随想录给的解法更容易懂)定义Long型的最大值和最小值。递归左半部分,递归右半部分。先找到最大数,作为节点。
2024-12-11 00:24:32
242
原创 代码随想录算法训练营第十六天 | 二叉树part04| 513.找树左下角的值、112.路径总和 、106.从中序与后序遍历序列构造二叉树
(3). 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题112.路径总和)前向遍历,先判断root.left!= null,因为要保证优先左边搜索。(2). 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。(1). 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。中序切割点前位置对应的前序,是左节点,后半部分是右子树。后序的最后一个,就是跟节点,同时作为切割点,切割中序。中序切割点前是左节点,切割点后是右子树。
2024-12-08 20:37:27
319
原创 代码随想录算法训练营第十五天 | 二叉树part03| 110.平衡二叉树 、 257. 二叉树的所有路径、404.左叶子之和、 222.完全二叉树的节点个数
本题自己的解法和题解略有区别,自己的写法依然遵循递归三部曲,定义两个方法来实现。二叉树这些题目什么时候定义两个方法分开写,什么时候只需要定义一个方法合并写?如果两个方法返回值类型一样,就可以考虑合并写,类型不一样就要分开写。是叶子节点,形成路径 "1->2->5",添加到 res。是叶子节点,形成路径 "1->3",添加到 res。节点 2 的右子节点(为空),不进行递归。根节点 1:paths = [1]回溯,paths = [1, 2]回溯,paths = [1]不是叶子节点,继续递归。
2024-12-01 21:47:10
330
原创 代码随想录算法训练营第十四天 | 二叉树part02| 226.翻转二叉树、 101. 对称二叉树、 104.二叉树的最大深度 、111.二叉树的最小深度
比如depth = depth>temp?在递归中,可以实现每一次都和上一次的值比较,如果更大就更新。这里想返回空值,写return不对,应该写return null。遇到需要一直更新至最大值的情况,记住会用三目运算符或Math.max实现。如果遇到更新到最小值的情况,记住会用三目运算符或Math.min实现。在递归中,可以实现每一次都和上一次的值比较,如果更大就更新。遇到需要一直更新至最大值的情况,记住会用三目运算符实现。记住更新到最小,就先定义成最大的数。3.确定单层递归的逻辑,就是。
2024-11-27 23:45:49
168
原创 代码随想录算法训练营第十三天 | 二叉树part01| 144.二叉树的前序遍历&后序遍历&中序遍历、102.二叉树的层序遍历
递归方法接收两个参数,节点和深度(用来判断这一层要插入几个数),层数递增,如果resList的大小小于层数,说明这一层还没添加,就定义一个新数组用于存放这一层,然后把这一层添加到resList里,然后往里面添加元素。然后完成递归方法(传入根节点和数组),拿前序遍历举例,先把根节点插入数组,然后再调用方法(传入左节点,数组),然后再调用方法(传入右节点,数组),实现递归。一个类里面,定义两个方法,在第一个方法里定义的变量,在第二个方法里是不能用的,如果想用就在所有方法外定义这个变量。接着左节点,右节点递归。
2024-11-26 23:57:18
191
原创 代码随想录算法训练营第十天 | 栈与队列part01| 232.用栈实现队列 、225. 用队列实现栈、 20. 有效的括号、1047. 删除字符串中的所有相邻重复项
就是用栈来存放,那么栈的目的,就是存放遍历过的元素,当遍历当前的这个元素的时候,去栈里看一下是不是遍历过相同数值的相邻元素。更快的方法是遍历左括号,让对应的右括号入栈,左括号遍历完之后,所有相应的右括号就在栈里了。push方法中,把第一个队列元素取出,全部放到队列2里,然后新添加的元素放到队列1里,再把队列2的元素返回队列1,就实现了后进的先出,和栈的排列方式一样。定义一个方法,用两个栈模拟队列,队列是先进先出,所以把一个栈的元素一个一个出栈,全部添加到另外一个栈里,堆放顺序就和队列一样了。
2024-11-22 19:26:48
546
原创 代码随想录算法训练营第九天 | 字符串part02| 151.翻转字符串里的单词、卡码网:55.右旋转字符串
这里想反转全部字符串,但是.charAt()返回值是char字符类型,值是不可变的,即不能直接修改一个基本数据类型的返回值。2.全部反转 在sb上原地操作,这个方法定义的时候输入参数除了定义输入的字符串,还要定义开始截止,为了下面逐个单词反转的时候调用,可以做到只反转其中一个单词。如果字符串就是字符串类型存储,并且不转数组,就用s.setCharAt(..., ...),逗号前面是要被赋值的**位置**,逗号后面是赋值的**值**所有反转字符串的题目都可以用:先全部反转,再局部反转,就能做到部分反转。
2024-11-22 12:53:01
401
原创 代码随想录算法训练营第八天 | 字符串part01| 344.反转字符串、541. 反转字符串II、卡码网:54.替换数字
题目要求在原数组修改,不新建新数组,所以不用返回。要想返回也可以把方法返回类型改成数组,并且新建一个数组用来存储新字符,最后返回这个新建的数组。char数组常用来表示字符串,所以还是数组形式,所以用.length。这道题可以直接用翻转函数做,也可以依然用数组+temp做。如果用数组,就要先把字符串转为字符数组,进行反转,最后再转回来。思路是每2k递加为一周期,在每2k中,左指针为周期开始,右指针为开始+k-1或数组结尾(选更小的)。方法返回类型是void,即没有返回类型,所以如果写返回值是不对的;
2024-11-21 00:03:20
227
原创 代码随想录算法训练营第六天 | 哈希表part01| 242.有效的字母异位词 、349. 两个数组的交集 、 202. 快乐数、1. 两数之和
遍历原数组,添加到map表里,遍历一个就求一个的(target-此数),如果map表出现了target-此数,就把两个数的键放到长度为2的数组里。此外,题目中把哈希表转为数组,是从网上搜的一行代码,如果不能背下来,自己写的话,可以另外申请一个数组,把哈希表的元素一个一个添加进去。这道题用哈希表的原因是,根据题目描述,如果出现了之前出现过的数,就进入了循环,就不是快乐数。思路是定义一个求每位平方和的方法,n调用这个方法,求出来的数添加到哈希表里,如果出现了出现过的元素,就返回false。
2024-11-19 13:16:38
580
原创 代码随想录算法训练营第三天 | 链表part01| 203.移除链表元素 ,707.设计链表 ,206.反转链表
是错误的, 一个给另外一个赋值,起码赋值的得存在,而newtail此时还不存在。思路是双指针法,一个pre一个cur,cur开始在头节点,pre开始为null,然后同时逐步移动,一次一次把每个箭头方向换过来。还有一个错误,”插入节点时,如果index大于链表长度,就不插入“,这里我的写法是return null;初始化一个空结点,值为0,指针指向head ListNode list=new ListNode(0,head);这道题,定义一个指针cur,只要指向的下一个不是空,就一直循环。
2024-11-18 18:29:47
280
原创 代码随想录算法训练营第二天 | 数组part02| 209.长度最小的子数组,59.螺旋矩阵II
对于中间的四个左闭右开,要提前定义每次的起始位置(开始x y都为0,而后随着圈数增大,逐次加1,因为圈在缩小)和offset(开始为1,表示填充到第一行倒数第二个,而后随着圈数增大,逐次加1,因为圈每次在缩小)定义圈数,while圈数小于等于n/2,每一圈再详细写每一次左闭右开。方法是:首先定义一个最大的整型数为最终结果,在循环里,每次找到符合条件的,就拿这个和最终结果比大小,把小的更新为最新的最终结果。完整思路是左指针遍历,一旦和大于目标,就开始减去窗口开端的数,同时更新长度,一直减到不大于目标后结束。
2024-11-14 15:00:22
217
原创 代码随想录算法训练营第一天 | 数组part01| 704. 二分查找,27. 移除元素,977.有序数组的平方
思路是定义左指针和右指针,定义它们的中间点,while循环判断(左指针在右指针旁边,就一直循环):如果中间的数大于目标,右指针更新到中间点左边;如果中间的数等于目标,返回中间点下标。应该创建一个新数组,大小和原来这个数组一样,把找到的大平方数赋值到新数组里,这样下一次比较还是用原来旧数组的数比较,不会受影响。这里我找到大的数之后,赋值给原来这个数组的最后一位,这样会导致下一次比较的时候,可能用的是更新的大平方数和其他数比较。定义左右指针,左右指针的数平方比大小,大的那个赋值到新数组,然后更新移动指针。
2024-11-13 14:45:19
430
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅