![](https://img-blog.csdnimg.cn/20201014180756754.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
hot100
leetcode hot100 刷题练习
GAcD
。
展开
-
114. 二叉树展开为链表
如果左链表最后一个结点为空,右链表最后一个结点不为空,返回右链表最后一个结点。返回右链表最后一个结点,如果右链表最后一个结点为空,就返回左链表最后一个结点。将右链表连接再左链表的最后一个结点上,将左链表放到右子树上。再将右子树展开为链表,返回链表的最后一个结点。将左子树展开为链表,返回链表的最后一个结点。如果两个链表最后一个结点都为空,返回根结点。原创 2024-03-30 10:05:04 · 217 阅读 · 1 评论 -
10种排序算法:题目+思路+代码+参考
每次随机选一个数作为标准位,这里选择左边界的数,左指针找到比标准位小(大)的数,右指针找到比标准位大(小)的数,两者交换,最终把数组分为两部分,左半部分都是比标准位大(小)的,右半部分都是比标准位小(大)的。外层循环表示扫描的趟数,每扫描一趟就有一个数到应该的位置,n个数所以扫描n趟,但当n-1个数都到正确的位置时,最后一个数也一定是在正确的位置,所以扫描n-1趟就行了。先统计出数组的最大值和最小值,然后将数组范围的数组映射到新的数组中,统计每一个数字出现的次数,最后按照顺序覆盖原数组即可。原创 2024-03-28 18:04:51 · 792 阅读 · 0 评论 -
42. 接雨水
双指针,左指针维护前缀的最大值,右指针维护后缀的最大值,包括当前位。然后如果前缀最大值小于后缀最大值,因为后缀的最大值只可能更大,不可能更小,所以左指针位置的贡献可以算出来了,同理右指针也一样。前后缀,先分别算出当前位置前缀的最大值和当前位置后缀的最大值,包括当前位置。然后再算出每个位置对最终答案的贡献,贡献等于前后缀最大值中最小的哪一个减去当前位置的高度。单调栈,从左到右单调递减栈,找到第一个大于栈顶的元素,栈顶依次出栈,计算贡献。左边界是栈顶的下一个元素,右边界是当前元素,还要乘以跨度。原创 2024-02-17 11:09:25 · 238 阅读 · 0 评论 -
4. 寻找两个正序数组的中位数
否则比较两个数组向后移动k/2位置的元素,将较小的那一个固定移动k/2,排除了k/2个元素,继续递归调用,找第k - 排除了的元素个数的元素的值。nums1第k/2个元素入果小于nums2第k/2个元素,那么nums前k/2个元素最大是k - 1个元素,不可能是第k个元素。如果有数组的长度为0,就返回另一个数组从起始位置往后数第k个元素。定义函数getKth,找到第k个元素的值。原创 2024-02-08 17:49:25 · 179 阅读 · 0 评论 -
84. 柱状图中最大的矩形
维护一个单调递增的栈,如果当前的元素比栈顶的元素小,说明栈顶的元素不能向右扩展,此时计算以栈顶元素为高的矩形的最大面积,宽只能向左扩展,左边界就是栈顶元素的下一个元素,因为栈顶和栈顶下一个元素之间的所有元素都已经弹出了,并且弹出的元素一定比二者都大,换种说法就是当放入当前栈顶元素的时候,把大于栈顶的元素都弹出栈了,剩下的栈顶的下一个元素一定是比弹出的都小,也比当前栈顶要小。单调栈任意相邻元素直接如果存在元素,一定都比二者大,并且都被弹出了。原创 2024-02-08 14:37:03 · 118 阅读 · 0 评论 -
23. 合并 K 个升序链表
将每一个链表的头结点放入优先队列中,然后每次从优先队列中取出队首元素,如果队首元素的next不为null就将next放入优先队列中。原创 2024-02-08 13:25:35 · 371 阅读 · 0 评论 -
146. LRU 缓存
put元素的时候,先通过HashMap获取结点的位置,如果存在,修改完结点值后移动至队首,如果不存在,就创建结点放入HashMap中并再队首插入结点,如果插入后的大小超过最大的大小就把队尾的结点删除,并移除HashMap中对应的元素。构造函数有三个参数。get元素的时候,先通过HashMap获取结点的位置,然后再返回值,最后将结点移动至队首。实现一个双向链表,实现队首插入结点,删除特定结点,结点移动至队首,删除队尾结点。使用HashMap维护key和对应结点在双向链表中的位置。原创 2024-02-08 12:28:11 · 220 阅读 · 0 评论 -
32. 最长有效括号
如果chs[i] = ')' chs[i - 1] = ')' dp[i - 1] > 0 dp[i] = dp[i - 1] + dp[i - 1 - dp[i - 1] - 1] + 2。如果chs[i] = ')' chs[i - 1] = '(' dp[i] = dp[i - 2] + 2。如果chs[i] = '(' 没有括号可以匹配dp[i] = 0。分解子问题:dp[i]表示以i结尾的最长有效括号。原创 2024-02-04 23:31:54 · 104 阅读 · 0 评论 -
72. 编辑距离
类似,当word1[i] == word2[j] 的时候,不需要二维操作,dp[i][j] = dp[i - 1][j - 1],否则需要对word1做三种操作,删除操作等于dp[i - 1][j] + 1,插入操作等于dp[i][j - 1] + 1,替换操作等于dp[i - 1][j - 1] + 1。对word1进行插入操作等于对word2进行删除操作。原创 2024-02-04 22:25:40 · 141 阅读 · 0 评论 -
1143. 最长公共子序列
所以状态转移方程为:dp[i][j] = text1.charAt(i) == text2.charAt(j)?表示当二者最后一个字符相等的时候,就等于各自上一个字符的最长长度加1,否则就等于text1字符减1和text2字符减1的最大值。动态规划,分解子问题:dp[i][j] 表示text1截止到i, text2截止饿到j,两者的最长公共子序列。原创 2024-02-04 21:41:45 · 315 阅读 · 0 评论 -
5. 最长回文子串
分解子问题:对于[i, j]范围的字符串,如果是字符串需要满足,s[i] == s[j] &&(j - i <= 1 || dp[i + 1][j - 1]),即,两边的两个字符相等,并且[i + 1, j - 1]范围的字符串也是回文字串,或者两边相等但长度只有1或者2。遍历一遍,以每一个元素为中心向两边扩散,或者以这个元素和这个元素的下一个元素为中心向两边扩散。所以状态转移方程为:dp[i][j] = s[i] == s[j] &&(j - i <= 1 || dp[i + 1][j - 1])。原创 2024-02-04 21:05:37 · 282 阅读 · 0 评论 -
64. 最小路径和
状态转移方程:dp[i][j] = min(dp[i + 1][j], dp[i][j + 1]) + grid[i][j]。初始化:dp[m - 1][i] 为后缀和, dp[i][n - 1] 为最后一列从下到上的后缀和。空间优化: dp[j] = min(dp[j], dp[j + 1]) + grid[i][j]。类似,只是状态转移方程和初始化不同。原创 2024-02-04 19:06:56 · 181 阅读 · 0 评论 -
62. 不同路径
初始化,i=m-1的时候dp[m-1][j] = 1,j = n - 1的时候dp[i][n - 1] = 1。遍历顺序,计算i,j的时候要先算出i + 1 和 j + 1,所以i从m-2到0,j从n-2到0。动态规划,dp[i][j] = dp[i + 1][j] + dp[i][j + 1]。空间优化 dp[i] = dp[i] + dp[i + 1]。原创 2024-02-04 18:47:22 · 119 阅读 · 0 评论 -
287. 寻找重复数
也可以使用二分答案的方法,对于每一个mid,遍历一遍数组找到小于等于mid的个数cnt,如果cnt = mid,说明[ l , mid ]区间没有重复的元素,答案在[ mid + 1, r ],否则说明重复的元素在[ l, mid ]中。将下标对应的数字作为当前数字的下一个数字,这样就得到了一个类似链表的结构。数字的范围是1-n,数组的下标范围是0-n,所以必定存在重复的数字。原创 2024-02-04 18:34:20 · 292 阅读 · 0 评论 -
31. 下一个排列
求下一个排列可以看做给一个数字,将位数重新排列,求出下一个更大的数字。2 将较小的那个数和较大的那个数右边从右向左第一个大于较小数的数交换。4 如果第1步没有找到,说明已经是最大的数字了,直接转为递减。1 从右向左找到第一个相邻的递增的两个数。3 把较大数及其右边从递减转为递增。原创 2024-02-04 17:32:43 · 196 阅读 · 0 评论 -
75. 颜色分类
方法4:三根指针,p0,p1用于归位0和1,p1和p2用于归位1和2。p1如果遇到2和结尾交换,如果p1从p2换到的可能还会继续换所以不能动。p1如果遇到0直接和开头交换,p1如果遇到1直接看下一位。方法3:三根指针,p0,p1用于归位0和1,i用于遍历,如果i遇到0就和p0交换,如果p0不等于p1,有可能把1交换到i的位置,需要在和p1交换一次。如果遇到1直接和p1交换就行。方法2:先遍历一遍把所有的0和头部的元素交换,然后再遍历一遍把所有的1和头部之后的元素交换,最后剩下的2就在最后了。原创 2024-02-04 14:11:13 · 217 阅读 · 0 评论 -
169. 多数元素
方法2:因为题目一定存在出现次数超过一半的数字,所以使用ans记录当前出现的最多的数字,最多的数字每出现一次cnt就加1,其他数字每出现一次cnt就减1,当cnt为0时,说明之前的区间被分为多段,每一段出现最多的数字和其他数字各占一半。因为题目答案一定存在,所以最后一段的出现次数最多的数字一定就是答案。方法1:使用hash表一边统计每个数字出现的次数,一边判断当前数字的个数是否已经超过了总个数的一半。如果超过了就是答案。原创 2024-02-04 12:14:14 · 256 阅读 · 0 评论 -
416. 分割等和子集
要等分和子集,数组的和必须是偶数,如果是奇数,一定不可能分割。计算好数组的和后,每个数字有选或者不选两种选择,要凑成sum。背包问题,从一些列数字中选取几个,使得和最接近sum。原创 2024-02-03 21:06:49 · 168 阅读 · 0 评论 -
152. 乘积最大子数组
由于存在负数,所以同时记录乘积最大和乘积最小子数组,取最大和最小值的时候,nums[i - 1]*nums[i],nums[i], 和 min[i - 1]*nums[i] 三个取最大和取最小。最长连续子序列,从前向后遍历一遍,有两种选择,一种是和前一个位置连在一起,另一种是另开一个子序列。原创 2024-02-03 20:29:51 · 168 阅读 · 0 评论 -
300. 最长递增子序列
求以i结尾的最长递增子序列的时候,遍历之前求出的每一个j结尾的最长递增子序列,如果i位置的数字比j大,就可以加入以j结尾的最长递增子序列。遍历的时候取最大值。每求出一个最长递增子序列,就更新一次ans。动态规划的时候可以遍历每一个已经求出的结果。使用数组dp记录以i结尾的最长递增子序列。原创 2024-02-03 19:29:03 · 174 阅读 · 0 评论 -
139. 单词拆分
4.1 t要从i + 1一直遍历到结尾,为了利用到之前算到的结果,所以i从后向前遍历,j从i+1遍历到结尾。2 递推公式:dfs(i) = s.substring(i, t) && dfs(t)4 转为动态规划 f[i] = s.substring(i, t) && f[t]4.2 初始化值f[n] = true 最终结果为f[0]1 思考子问题:dfs(i)表示,从i到结尾的字串能否拆分。子问题-->递推公式-->记忆化搜索-->动态规划。动态规划:递推公式-->遍历顺序-->返回值。原创 2024-02-03 18:35:20 · 124 阅读 · 0 评论 -
322. 零钱兑换
从1开始计算每一个金额,对于金额i,从小到大遍历每一个coin,dp[i] = Math.max(dp[i], dp[i - conis[j]] + 1),1表示使用了一次coins[j]。还可以从多重背包的角度考虑。原创 2024-02-02 12:55:41 · 195 阅读 · 0 评论 -
279. 完全平方数
对于数字n,遍历每一个平方数,答案等于Math.max(dp[n], dp[n - j*j] + 1);1 是当前这个平方数j*j。所以从1开始把每一个数的结果算出来,然后推出答案。数字n最大可以由n个1组成,dp[n] = n;动态规划只是利用已经算出的结果,与穷举不冲突。原创 2024-02-02 12:03:06 · 164 阅读 · 0 评论 -
198. 打家劫舍
当前位置的最高金额取决于上一个位置是否偷窃了,如果偷窃了,当前位置就不能偷窃了,如果没有偷窃,当前位置就必须偷窃。原创 2024-02-02 11:26:22 · 137 阅读 · 0 评论 -
118. 杨辉三角
杨辉三角的特点:第i行有i个数,i从1开始;第i行第一个和最后一个数是1,其余的数由上一行计算出的结果算出。特点:第i行有i个数,i从1开始;第i行第一个和最后一个数是1,其余的数由上一行计算出的结果算出。在计算每一行的时候如果是0或者i,即是第一个数或者是最后一个数,结果是1.第二层循环更表示第i行的第几个数,从1开始,最大是i。所以用两层循环,第一层循环表示第i行,从1开始。否则由上一行的同一列和上一列相加得出。原创 2024-02-02 11:10:13 · 162 阅读 · 0 评论 -
763. 划分字母区间
类似,不断更新最大的达到的范围,如果当前的i等于最大的范围,就说明当前是一个有效的分割,加入答案。原创 2024-02-02 10:48:40 · 167 阅读 · 0 评论 -
45. 跳跃游戏 II
使用两个变量,range是当前最大可以到达的范围,nextRange是下一个可以到达的范围。如果超了当前最大可以到达的范围,就把range更新为nextRange,步数加1。原创 2024-02-01 21:12:50 · 147 阅读 · 0 评论 -
55. 跳跃游戏
一步一步走,更新可以达到的最大范围。如果当前这一步不在最大范围之内就返回false。原创 2024-02-01 20:37:38 · 202 阅读 · 0 评论 -
121. 买卖股票的最佳时机
维护截止当前为止的最小值,每天都尝试卖出,求最大利润。原创 2024-02-01 19:07:35 · 176 阅读 · 0 评论 -
347. 前 K 个高频元素
如果小根堆的大小大于等于k,就比较堆顶元素出现的次数和当前元素出现的次数。如果当前出现的次数大于堆顶元素出现的次数就放入,并且弹出堆顶,否则不处理。然后将数字和出现的次数一起放入小根堆中。先使用map统计一遍元素出现的次数。如果小根堆的大小小于k,直接放入。原创 2024-02-01 18:54:40 · 124 阅读 · 0 评论 -
295. 数据流的中位数
例如数组:1, 2, 3, 4 中位数等于 (2 + 3)/ 2,如果在首尾添加元素: 0, 1, 2, 3, 4, 5 中位数依然不变,所以使用两个堆。所以中位数要么是que1的堆顶,要么是que1和que2的堆顶的平均数。que1 大顶堆,维护前半部分的数字,小于等于中位数。que2 小顶堆,维护后半部分的数字,大于中位数。que1 的 大小总比 que2 大1或者相等。对顶堆可以动态维护数组的中位数。数据结构堆的经典应用。原创 2024-02-01 12:02:27 · 186 阅读 · 0 评论 -
394. 字符串解码
如果遇到 [ ,先将当前的处理结果暂存在stack1中,同时将即将重复的次数k加入stack2中,将ans置为空,将k置为0,表示处理下一个解码字符串,等待处理好了以后再从stack2中取出拼接起来。如果遇到 ] ,取出stack中的k,然后重复以后,将暂存在stack2中的取出,与刚刚处理好的拼接起来。从左向右遍历一遍字符串的所有字符,使用ans记录截止当前位置的解码字符串。如果是普通字母,就加入ans。如果遇到数字就加入k中。原创 2024-01-31 21:59:27 · 214 阅读 · 0 评论 -
739. 每日温度
单调栈模板题,维护一个单调递减栈,当出现大于栈顶的元素的时候栈中元素依次出栈,出栈的时候更新答案数组为当前下标减去栈顶的下标。单调栈考虑递增还是递减,从左向右还是从右向左。原创 2024-01-31 19:19:24 · 173 阅读 · 0 评论 -
20. 有效的括号
遍历每一个字符,如果是左括号,就向栈中存入右括号,这样当遇到右括号的时候,就不需要逐一判断每一种类型的左括号,只要判断是否于栈中需要的右括号一致即可。遇到左括号存入右括号表示想要匹配,下一个需要遇到的括号类型。这样只需要判断相等就可以了,不需要判断括号的类型。原创 2024-01-31 10:49:34 · 105 阅读 · 0 评论 -
153. 寻找旋转排序数组中的最小值
就是找到第一个小于nums[0]的位置,可以把数组水平划分为两个部分,上半部分是大于等于nums[0]的,下半部分是小于nums[0]的。也可以看作左半部分是大于等于nums[0]的,右半部分是小于nums[0]的。二分的本质不是单调性,是两段性。原创 2024-01-30 15:30:24 · 156 阅读 · 0 评论 -
33. 搜索旋转排序数组
因为原数组是升序排列的。所以可以把数组分为两部分,一部分大于等于nums[0],另一部分小于nums[0]。然后通过判断target和nums[0]的大小关系,判断是在左半部分还是右半部分。先通过一次二分找到第一个小于nums[0]的位置。再进行一次二分,最终找到答案。二分的本质是两段性不是单调性。原创 2024-01-30 15:22:35 · 133 阅读 · 0 评论 -
34. 在排序数组中查找元素的第一个和最后一个位置
使用两次二分查找,第一次找大于等于target的第一个位置,第二次找大于等于target + 1的第一个位置-1。二分条件可以灵活地转换。原创 2024-01-30 13:05:10 · 157 阅读 · 0 评论 -
74. 搜索二维矩阵
方法1:可以使用两次二分,先在第一列上二分,然后确定第一个小于等于target的行r,然后再在r行上二分,找到第一个小于等于target的值t。如果r不存在或者t不存在,返回false,否则返回true。方法2:把二维数组通过坐标变换转为一维数组,使用一次二分就行了。原创 2024-01-30 12:22:00 · 250 阅读 · 0 评论 -
35. 搜索插入位置
l的左边是小于target的所有值,l的右边是大于等于target的所有值。r的右边是大于等于target的所有值,r的左边是小于target的所有值。题目要求找到第一个大于等于target的位置。l 和 r 的含义是需要和题目一致的。原创 2024-01-30 12:05:39 · 224 阅读 · 0 评论 -
51. N 皇后
在每一行尝试放在每一列,检查这个位置是否可以放,如果可以就继续向下遍历,否则跳过,检查当前位置的上方,左上和右上是否存在棋子,从而判断当前位置是否可以放置棋子。使用二维数组map记录当前已经摆放了棋子的位置。当可以遍历到最后一行后,将path加入答案。使用回溯遍历每一种情况。原创 2024-01-29 10:11:08 · 110 阅读 · 0 评论