LeetCode 热题 HOT 100 题解(仅记录解题思路)

链接:

🔥 LeetCode 热题 HOT 100 - 力扣(LeetCode)全球极客挚爱的技术成长平台

简单(21道):

160. 相交链表

检查两个链表是否相交

方法一:哈希

首先将A的所有结点存储在哈希表中,接着遍历B,如果B的某个结点存在于哈希表中,则证明相交;

方法二:双指针

指针p1从A的头结点出发,指针p2从B的头结点出发;当p1不为null时,指向下一个;当p1为null时,指向B的开始。p2同理。直到2个指针指向同一个结点(有交点)或者同时指向为null(无交点)。

234. 回文链表

方法一:将值复制到数组中后用双指针法

方法二:快慢指针

指针p1和p2开始都指向第一个结点,然后p1每次移动1步,p2则2步,当p2移到末尾时,则p1到中间位置,接着反转后半部分,并与前半部分比较。

226. 翻转二叉树

方法一:递归

如果左右两棵子树都已实现了反转,那么仅仅交换其位置即可。

206. 反转链表

方法一:递归

在遍历链表时,将当前节点的 next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。

169. 多数元素

方法一:哈希

遍历一遍数组nums,存在哈希表中,相同元素+1;接着再遍历一次哈希表,找出最大值

方法二:排序 

对数组进行排序,那么下标为 ⌊n/2​⌋ 的元素(下标从 0 开始)一定是众数。

方法三:随机化

随机挑选一个值,检查其是否是众数;不是则重新随机。

141. 环形链表

方法一:哈希表

从头结点出发,检索当前结点是否在哈希表中,若不再,则加入;若在,则表示有环

方法二:快慢指针

指针p1在头结点处,指针p2在头结点的next处,然后p1每次移动1格,p2则走2步,若在其中一个进入null之前两者指向同一结点,则代表有环。 

136. 只出现一次的数字

方法一:集合增删

使用集合存储数字。遍历数组中的每个数字,如果集合中没有该数字,则将该数字加入集合,如果集合中已经有该数字,则将该数字从集合中删除,最后剩下的数字就是只出现一次的数字。

方法二:哈希

使用哈希表存储每个数字和该数字出现的次数。遍历数组即可得到每个数字出现的次数,并更新哈希表,最后遍历哈希表,得到只出现一次的数字。

方法三:集合求和

使用集合存储数组中出现的所有数字,并计算数组中的元素之和。由于集合保证元素无重复,因此计算集合中的所有元素之和的两倍,即为每个元素出现两次的情况下的元素之和。由于数组中只有一个元素出现一次,其余元素都出现两次,因此用集合中的元素之和的两倍减去数组中的元素之和,剩下的数就是数组中只出现一次的数字。

方法四:位运算

因此对于出现次数为偶数的元素,执行连续位运算的最后结果是0,而对于出现次数为奇数的元素,最后当然就被保存下来了。

C++ 提供了 6 种位运算符,包括按位与(&)、按位或(| )、按位异或(^)、取反(~)、左移(<<)、右移(>>)

461. 汉明距离

方法一:使用内置函数

__builtin_popcount(a^b)

方法二:移位实现位计数

while (s) {
            ret += s & 1;
            s >>= 1;
}

方法三:每次都去掉最右侧的1

        while (s) {
            s &= s - 1;
            ret++;
        } 

448. 找到所有数组中消失的数字

方法一:哈希

方法二:直接对数组进行修改

具体来说,遍历 nums,每遇到一个数 x,就让 nums[x−1] 增加 n。由于 nums 中所有数均在 [1,n] 中,增加以后,这些数必然大于 n。最后我们遍历 nums,若 nums[i] 未大于 n,就说明没有遇到过数 i+1。这样我们就找到了缺失的数字。

338. 比特位计数

方法一: 移位实现位计数

方法二: 每次都去掉最右侧的1

方法三: 动态规划——最高有效位

不同于暴力搜索,动态规划是一种用一个状态代表一类情况的方法。我们观察到对于1011而言,其1的位数其实相当于(1011-1000)中1的位数+1。我们称1、10、100、1000这种2的整数次幂代表最高有效位highBit。状态转移公式为bits[i]=bits[i−highBit]+1。而一个数是否是最高有效位只需要通过i&(i-1)==0判断即可。

方法四: 动态规划——最低有效位

奇数中1的个数 = 偶数(奇数-1)中1的个数 + 1; 例如 111 110

偶数中1的个数 = 偶数/2中1的个数; 例如 1000 100

因此状态转移方程为bits[i]=bits[i>>1]+i&1

方法五: 动态规划——最低设置位

我们观察到对于1011而言,其1的位数相当于去掉最右侧1后1010中1的位数+1。状态转移公式为bits[i]=bits[i&(i-1)]+1。

121. 买卖股票的最佳时机

方法一:一次遍历

假设我们要在第i天卖出股票,那么自然我们希望股票是在这天之前的低谷买入的,因此我们只需要在遍历的同时维护一个前面天中的低谷,不断更新即可。 

283. 移动零

方法一:双指针法

使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。

右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。

注意到以下性质:

左指针左边均为非零数;

右指针左边直到左指针处均为零。

因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。

543. 二叉树的直径

方法一:DFS

首先我们知道一条路径的长度为该路径经过的节点数减一,所以求直径(即求路径长度的最大值)等效于求路径经过节点数的最大值减一。

而任意一条路径均可以被看作由某个节点为起点,从其左儿子和右儿子向下遍历的路径拼接得到。

21. 合并两个有序链表

方法一:递归(也可以认为是双指针)

20. 有效的括号

方法一:用栈模拟即可

617. 合并二叉树

方法一:DFS

可以使用深度优先搜索合并两个二叉树。从根节点开始同时遍历两个二叉树,并将对应的节点进行合并。

两个二叉树的对应节点可能存在以下三种情况,对于每种情况使用不同的合并方式。

如果两个二叉树的对应节点都为空,则合并后的二叉树的对应节点也为空;

如果两个二叉树的对应节点只有一个为空,则合并后的二叉树的对应节点为其中的非空节点;

如果两个二叉树的对应节点都不为空,则合并后的二叉树的对应节点的值为两个二叉树的对应节点的值之和,此时需要显性合并两个节点。

对一个节点进行合并之后,还要对该节点的左右子树分别进行合并。这是一个递归的过程。

104. 二叉树的最大深度

方法一:DFS

如果我们知道了左子树和右子树的最大深度 l 和 r,那么该二叉树的最大深度即为max(l,r)+1。而左子树和右子树的最大深度又可以以同样的方式进行计算。

因此我们可以用「深度优先搜索」的方法来计算二叉树的最大深度。具体而言,在计算当前二叉树的最大深度时,可以先递归计算出其左子树和右子树的最大深度,然后在 O(1) 时间内计算出当前二叉树的最大深度。递归在访问到空节点时退出。

101. 对称二叉树

方法一:递归

94. 二叉树的中序遍历

方法一:递归

1. 两数之和

方法一:哈希

70. 爬楼梯

方法一:动态规划

方法二:矩阵快速幂

方法三:通项公式

中等(66道):

236. 二叉树的最近公共祖先

方法一:递归

方法二:存储父结点然后向上遍历

739. 每日温度

方法一:暴力

反向遍历温度列表。对于每个元素 temperatures[i],在数组 next 中找到从 temperatures[i] + 1 到 100 中每个温度第一次出现的下标,将其中的最小下标记为 warmerIndex,则 warmerIndex 为下一次温度比当天高的下标。如果 warmerIndex 不为无穷大,则 warmerIndex - i 即为下一次温度比当天高的等待天数,最后令 next[temperatures[i]] = i。

例如,反向遍历开始,对于73而言,从74~100全是无穷大,因此res[7]=0,next[73]=7;接着是76,从77~100全是无穷大,因此res[6]=0,next[76]=6;接着是72,从73~100发现角标最小的是next[76]=6,因此res[5]=next[76]-5=1,next[72]=5,其他以此类推。

方法二:单调栈

当我们聚焦在某个元素x上时,我们只关心在x右侧且比x值要大的离x最近的值。例如75,71,69,72,76,78,对于75而言,我们只关心76的存在,75~76中间的其他值对75都没意义。因此我们可以开辟一个单调栈,从栈底到栈顶的下标对应的温度列表中的温度依次递减。如果一个下标在单调栈里,则表示尚未找到下一次温度更高的下标。

221. 最大正方形

方法一:暴力

将每一个方格分别视为正方形的左上角,如果是0,继续下一个;如果是1,开始尝试延申边长,并加以判断是否满足全为0的条件。

方法二:动态规划

我们用 dp(i,j) 表示以 (i,j) 为右下角,且只包含 1 的正方形的边长最大值。如果我们能计算出所有 dp(i,j) 的值,那么其中的最大值即为矩阵中只包含 1 的正方形的边长最大值,其平方即为最大正方形的面积。

先来阐述简单共识

  • 若形成正方形(非单 1),以当前为右下角的视角看,则需要:当前格、上、左、左上都是 1
  • 可以换个角度:当前格、上、左、左上都不能受 0 的限制,才能成为正方形

上面详解了 三者取最小 的含义:

图 1:受限于左上的 0
图 2:受限于上边的 0
图 3:受限于左边的 0
数字表示:以此为正方形右下角的最大边长
黄色表示:格子 ? 作为右下角的正方形区域
就像 木桶的短板理论 那样——附近的最小边长,才与 ? 的最长边长有关。

如上图所示,状态转移方程为:

注意对于边缘元素(i==0||j==0)要记得初始化为1,否则就执行上述的状态转移方程即可。

215. 数组中的第K个最大元素

方法一:快排(不用sort,手搓找到第k个最大元素即可)

方法二:构建大顶堆,做 k−1 次删除操作后堆顶元素就是我们要找的答案。 

208. 实现 Trie (前缀树)

方法一:字典树

207. 课程表

200. 岛屿数量

198. 打家劫舍

238. 除自身以外数组的乘积

155. 最小栈

152. 乘积最大子数组

148. 排序链表

146. LRU 缓存

142. 环形链表 II

139. 单词拆分

647. 回文子串

128. 最长连续序列

322. 零钱兑换

494. 目标和

438. 找到字符串中所有字母异位词

437. 路径总和 III

416. 分割等和子集

406. 根据身高重建队列

399. 除法求值

394. 字符串解码

347. 前 K 个高频元素

337. 打家劫舍 III

309. 买卖股票的最佳时机含冷冻期

300. 最长递增子序列

287. 寻找重复数

279. 完全平方数

253. 会议室 II

240. 搜索二维矩阵 II

22. 括号生成

49. 字母异位词分组

48. 旋转图像

46. 全排列

39. 组合总和

34. 在排序数组中查找元素的第一个和最后一个位置

33. 搜索旋转排序数组

31. 下一个排列

538. 把二叉搜索树转换为累加树

560. 和为 K 的子数组

19. 删除链表的倒数第 N 个结点

17. 电话号码的字母组合

15. 三数之和

11. 盛最多水的容器

5. 最长回文子串

3. 无重复字符的最长子串

2. 两数相加

79. 单词搜索

114. 二叉树展开为链表

621. 任务调度器

105. 从前序与中序遍历序列构造二叉树

102. 二叉树的层序遍历

98. 验证二叉搜索树

96. 不同的二叉搜索树

78. 子集

75. 颜色分类

72. 编辑距离

581. 最短无序连续子数组

64. 最小路径和

62. 不同路径

56. 合并区间

55. 跳跃游戏

53. 最大子数组和

困难(13道):

1. Two Sum 2. Add Two Numbers 3. Longest Substring Without Repeating Characters 4. Median of Two Sorted Arrays 5. Longest Palindromic Substring 6. ZigZag Conversion 7. Reverse Integer 8. String to Integer (atoi) 9. Palindrome Number 10. Regular Expression Matching 11. Container With Most Water 12. Integer to Roman 13. Roman to Integer 14. Longest Common Prefix 15. 3Sum 16. 3Sum Closest 17. Letter Combinations of a Phone Number 18. 4Sum 19. Remove Nth Node From End of List 20. Valid Parentheses 21. Merge Two Sorted Lists 22. Generate Parentheses 23. Swap Nodes in Pairs 24. Reverse Nodes in k-Group 25. Remove Duplicates from Sorted Array 26. Remove Element 27. Implement strStr() 28. Divide Two Integers 29. Substring with Concatenation of All Words 30. Next Permutation 31. Longest Valid Parentheses 32. Search in Rotated Sorted Array 33. Search for a Range 34. Find First and Last Position of Element in Sorted Array 35. Valid Sudoku 36. Sudoku Solver 37. Count and Say 38. Combination Sum 39. Combination Sum II 40. First Missing Positive 41. Trapping Rain Water 42. Jump Game 43. Merge Intervals 44. Insert Interval 45. Unique Paths 46. Minimum Path Sum 47. Climbing Stairs 48. Permutations 49. Permutations II 50. Rotate Image 51. Group Anagrams 52. Pow(x, n) 53. Maximum Subarray 54. Spiral Matrix 55. Jump Game II 56. Merge k Sorted Lists 57. Insertion Sort List 58. Sort List 59. Largest Rectangle in Histogram 60. Valid Number 61. Word Search 62. Minimum Window Substring 63. Unique Binary Search Trees 64. Unique Binary Search Trees II 65. Interleaving String 66. Maximum Product Subarray 67. Binary Tree Inorder Traversal 68. Binary Tree Preorder Traversal 69. Binary Tree Postorder Traversal 70. Flatten Binary Tree to Linked List 71. Construct Binary Tree from Preorder and Inorder Traversal 72. Construct Binary Tree from Inorder and Postorder Traversal 73. Binary Tree Level Order Traversal 74. Binary Tree Zigzag Level Order Traversal 75. Convert Sorted Array to Binary Search Tree 76. Convert Sorted List to Binary Search Tree 77. Recover Binary Search Tree 78. Sum Root to Leaf Numbers 79. Path Sum 80. Path Sum II 81. Binary Tree Maximum Path Sum 82. Populating Next Right Pointers in Each Node 83. Populating Next Right Pointers in Each Node II 84. Reverse Linked List 85. Reverse Linked List II 86. Partition List 87. Rotate List 88. Remove Duplicates from Sorted List 89. Remove Duplicates from Sorted List II 90. Intersection of Two Linked Lists 91. Linked List Cycle 92. Linked List Cycle II 93. Reorder List 94. Binary Tree Upside Down 95. Binary Tree Right Side View 96. Palindrome Linked List 97. Convert Binary Search Tree to Sorted Doubly Linked List 98. Lowest Common Ancestor of a Binary Tree 99. Lowest Common Ancestor of a Binary Search Tree 100. Binary Tree Level Order Traversal II
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值