主要分章节记录了LeetCode的题,看题目的话可以从第二章开始
1、这组数据有什么样的特征?
有没有可能包含有大量重复的元素?
如果有这种可能的话,三路快排是更好地选择。(Java种快排的基本实现就是使用三路快排)
是否大部分数据距离它正确的位置很近?是否近乎有序?
如果是这样的话,插入排序是更好地选择。(如对银行的业务按照业务发生的时间进行排序,大多数业务先发生也先结束,少数处理的业务先发生但是处理时间较长后结束)
是否数据的取值范围非常有限?比如对学生成绩排序。
如果是这样的话,计数排序是更好地选择。
2、对排序有什么额外的要求?
是否需要稳定排序?
如果是的话,归并排序是更好地选择。
3、数据的存储状况是怎样的?
注:快排非常依赖于数组的随机存取
是否是使用链表存储的?
如果是的话,归并排序是更好地选择。
数据的大小是否可以装载在内存里?
数据量很大,或者内存很小,不足以装载在内存里,需要使用外排序算法。
在很多情况下,基础的普通的快排都不是最优的选择,甚至在一些情况下,快排根本是不适用的,在工作中真实的处理一个问题,就需要考虑各种各样的条件。关键在于你所表达出的解决问题的思路。
并不需要啃完一本《算法导论》,强调理论证明。
看书的时候重思想,轻理论
高级数据结构和算法面试提及的概率很低(第一轮)
红黑树
计算集和
B-Tree
斐波那契堆
数论
FFT
那么算法面试的准备范围是什么?
不要轻视基础算法和数据结构,而是关注“有意思”的题目。
各种排序算法
基础的数据结构和算法实现:堆、二叉树、图…
基础数据结构的使用:链表、栈、队列、哈希表、图、trie、并差集…
基础算法:深度优先、广度优先、二分查找、递归…
基础算法思想:递归、分治、回溯搜索、贪心、动态规划…
在学习和实践做题之间要掌握平衡。不要只关注于题目的正确与否(只刷题),更要注重其中的算法思想。
注意题目中的条件。
比如给定一个有序数据…
是不是能用二分查找法来进行相关的搜索
有一些题目中的条件本质是暗示
设计一个O(nlogn)的算法
八成离不开分治法,也就是在一棵搜索树中完成任务
这个O(nlogn)是不是对一个数组排序的时间复杂度,我们是不是要先对整个数组进行排序,然后看有没有可能在O(n)或者O(logn)的时间复杂度下完成其他的任务
无需考虑额外的空间
是不是需要开辟额外的空间,用空间换时间
数据规模大概是10000
设计O(n2)的算法就可以解决这个问题,这是因为对于O(n2)的算法完全可以处理百万级甚至是千万级的数据
当没有思路的时候,给自己几个简单的测试用例,试验一下;
不要忽视暴力解法,暴力解法通常是思考的起点。
**优化算法。**遍历常见的算法思路,遍历常见的数据结构,空间和时间的交换(哈希表),对数据进行预处理(排序)。在瓶颈处寻找答案:O(nlogn)+ O(n^2) ; O(n^3)。
1、极端条件的判断。数组为空,字符串为空?数量为0?指针为NULL等等
2、变量名最好具有语义
3、代码的模块化,复用性等等
对撞指针
283. 移动零
非原地
原地
k - [0…k)中保存所有当前遍历过的非0元素
将非0元素与0元素进行交换位置
优化:如果所有元素都是0,就不需要交换——增加一个判断
27. 移除元素
如何定义删除?从数组中去除?还是放在数组末尾?剩余元素的排列是否要保证原有的相对顺序?是否有空间复杂度的要求? O(1)
26. 删除有序数组中的重复项
80. 删除有序数组中的重复项 II
75. 颜色分类
计数排序
三路快排
88. 合并两个有序数组
215. 数组中的第K个最大元素
整数序列不一定有序(利用快排partition中,将pivot放置在了其正确的位置上的性质)
167. 两数之和 II - 输入有序数组
该题保证有解且唯一一个解。
如果没有解怎样?保证有解;如果有多个解怎样?返回任意解
最直接的思考:暴力解法(超时)。双层遍历,O(n^2)
暴力解法没有充分利用原数组的性质――有序
有序?二分搜索?
对撞指针
125. 验证回文串
对于字符串常见的问题:空字符串如何看?字符的定义?大小写问题?
344. 反转字符串
类似:翻转一个数组
345. 反转字符串中的元音字母
这里元音不包含y
11. 盛最多水的容器
对撞指针
209. 长度最小的子数组
什么叫子数组(不要求连续,该题说的连续子数组);如果没有解怎么办?该题要求最短的连续子数组的长度,因此没有解就返回0(但如果要求最短的连续子数组,就有可能有多个解,那如果有多个解是只返回一个解还是返回所有解,返回一个解的话有没有特殊限定,返回所有解的话顺序是怎么样的)
暴力解
遍历所有的连续子数组[i.….j]
计算其和sum,验证sum >= s
时间复杂度O(n^3)
优化暴力解︰O(^2)?
滑动窗口
时间复杂度: O(n)
二分搜索
3. 无重复字符的最长子串
字符集?只有字母?数字+字母? ASCII?大小写是否敏感?
滑动窗口
如何记录重复字符? freq[256]
438. 找到字符串中所有字母异位词
字符集范围?英文小写字母;返回的解的顺序?任意。
滑动窗口
76. 最小覆盖子串
字符集范围?若没有解?返回"";若有多个解?保证只有一个解;什么叫包含所有字符? S = "“a”,T = “aa”
滑动窗口
数组中的问题其实最常见
排序︰选择排序;插入排序;归并排序;快速排序
查找:二分查找法
数据结构︰栈;队列;堆
如何写出正确的程序
明确变量的含义
循环不变量
小数据量调试
大数据量测试
349. 两个数组的交集
350. 两个数组的交集 II
242. 有效的字母异位词
空串?字符集?
202. 快乐数
290. 单词规律
给出一个模式(pattern)以及一个字符串,判断这个字符串是否符合模式?
字符集? 空串符合任意模式?还是不符合任意模式?
205. 同构字符串
字符集? 空串?是否可以一个字母映射到自己?
451. 根据字符出现频率排序
1. 两数之和
暴力解法(n^2)
排序后,使用双索引对撞:O(nlogn) + O(n)= O(nlogn)
查找表。将所有元素放入查找表,之后对于每一个元素a,查找target - a是否存在。(Map)
索引从O开始计算还是从1开始计算? 没有解怎么办? 有多个解怎么办?保证有唯一解
15. 三数之和
不同的三元组(索引不同还是值不同)?如果有多个解,解的顺序?如果没有解?
18. 四数之和
16. 最接近的三数之和
如果有多个解,其和target值的接近程度一样怎么办? 如果没解?(可不可能没解?)
454. 四数相加 II
暴力解法:O(n^4)
将D中的元素放入查找表:O(n^3)
将C+D的每一种可能放入查找表:O(n^2)
将A+B和C+D的每一种可能放入两个查找表(n^2)
49. 字母异位词分组
字符集取值范围?大小写敏感?
447. 回旋镖的数量
149. 直线上最多的点数
点坐标的范围(防止越界)?点坐标的表示(整数?浮点数?浮点误差?)
219. 存在重复元素 II
暴力解法:O(n^2)
滑动窗口 + 查找表
217. 存在重复元素
220. 存在重复元素 III
206. 反转链表
92. 反转链表 II
m和n超过链表范围怎么办? m >n怎么办?
83. 删除排序链表中的重复元素
86. 分隔链表
328. 奇偶链表
2. 两数相加
数字中是否有前置的0。(除0以外,没有前置0);负数?
445. 两数相加 II
如果不允许修改输入的链表呢? 使用辅助数据结构
203. 移除链表元素
82. 删除排序链表中的重复元素 II
21. 合并两个有序链表
24. 两两交换链表中的节点
对于考察链表的问题,如果没有特殊声明,只能对节点进行操作,不能修改节点的值
思考∶可不可以不用next指针?
25. K 个一组翻转链表
147. 对链表进行插入排序
148. 排序链表
写一个排序算法,用O(nlogn)的时间复杂度为一个链表进行排序——归并排序(自顶向上)更容易应用于链表
237. 删除链表中的节点
双指针技术
19. 删除链表的倒数第 N 个结点
n从0计还是从1计? n不合法,负数或者大于链表长度如何处理(保证n合法)
解法1∶先遍历一遍计算链表长度;再遍历一遍删除倒数第n个节点
Time:O(n);Space:O(1)
遍历两遍链表。能否只遍历一遍链表?
解法2:双指针
61. 旋转链表
143. 重排链表
链表无法随机访问数据,如何获得中间的元素? 两次遍历? 一次遍历?
234. 回文链表
能否使用O(1)的空间复杂度解决问题?
栈的基础使用
20. 有效的括号
栈顶元素反映了在嵌套的层次关系中,最近的需要匹配的元素
150. 逆波兰表达式求值
运算的种类(+,-,*,/) ?字符串表达的数字种类(整数)?
71. 简化路径
这个路径是否一定合法?
不能回退的情况?(如/…/,返回/)
多余的/?(如/homel/hello/,返回/home/hello )
栈和递归的紧密关系
使用栈模拟系统栈,写出非递归程序
144. 二叉树的前序遍历
94. 二叉树的中序遍历
145. 二叉树的后序遍历
341. 扁平化嵌套列表迭代器
队列 Queue
队列的基本应用-广度优先遍历
树﹔层序遍历
图﹔无权图的最短路径
用队列实现对一个二叉树进行层序遍历
102. 二叉树的层序遍历
107. 二叉树的层序遍历 II
103. 二叉树的锯齿形层序遍历
199. 二叉树的右视图
BFS和图的最短路径
279. 完全平方数
没有解怎么办? 是否可能没有解?
127. 单词接龙
126. 单词接龙 II
优先队列
347. 前 K 个高频元素
最简单的思路:扫描—遍统计频率;排序找到前k个出现频率最高的元素。O(nlogn)
思路2:维护优先队列,时间复杂度:O(nlogk)
维护一个含有k个元素的优先队列。如果遍历到的元素比队列中的最小频率元素的频率高,则取出队列中最小频率的元素,将新元素入队。最终,队列中剩下的,就是前k个出现频率最高的元素。
思路3:维护优先队列,时间复杂度:O(nlog(n-k))
23. 合并K个升序链表
简单树形与递归
104. 二叉树的最大深度
111. 二叉树的最小深度
226. 翻转二叉树
100. 相同的树
101. 对称二叉树
222. 完全二叉树的节点个数
**完全二叉树:**除了最后一层,所有层的节点数达到最大,与此同时,最后一层的所有节点都在最左侧。(堆使用完全二叉树)
**满二叉树:**所有层的节点数达到最大。
110. 平衡二叉树
**平衡二叉树:**每一个节点的左右子树的高度差不超过1
注意递归的终止条件
112. 路径总和
递归终止条件:①空树 ②叶子结点,即根的左右子树都为空
404. 左叶子之和
复杂树形与递归
257. 二叉树的所有路径
113. 路径总和 II
129. 求根节点到叶节点数字之和
更复杂的递归逻辑
437. 路径总和 III
其中路径不一定要起始于根节点;终止于叶子节点。路径可以从任意节点开始,但是只能是向下走的。
乍一看和之前的
路径总和
是一样的,但这里区别在于在这个问题中,对路径的定义更加宽松。结点之和可能会出现负数
二分搜索树中的问题
请大家复习二分搜索树中的基本操作:
插入、查找、删除
最大值,最小值minimum, maximum
前驱,后继successor,predecessor
上界,下界floor, ceil
某个元素的排名rank
寻找第k大(小)元素select
**二分搜索树:**每个节点的键值大于左孩子;每个节点的键值小于右孩子;以左右孩子为根的子树仍为二分搜索树
235. 二叉搜索树的最近公共祖先
①题目要求p和q不为空(如果为空的话怎么运转,比如直接返回一个空?) ②p和q的结点一定存在这棵树中,如果根本不在这棵树上的话,
return null
,所以要确保题目给的p和q都在这棵树上
98. 验证二叉搜索树
450. 删除二叉搜索树中的节点
若删除的节点不存在? 是否可能有多个需要删除的节点? 删除的节点是否需要返回?
108. 将有序数组转换为二叉搜索树
230. 二叉搜索树中第K小的元素
236. 二叉树的最近公共祖先
递归调用的一个重要特征–要返回(回溯)
回溯法是暴力解法的一个主要实现手段
树形问题
17. 电话号码的字母组合
字符串的合法性;空字符串;多个解的顺序
时间复杂度∶3^n = O(2^n)
93. 复原 IP 地址
131. 分割回文串
用回溯解决排列问题
46. 全排列
47. 全排列 II
用回溯解决组合问题
77. 组合
优化:取4时是没有必要的
39. 组合总和
40. 组合总和 II
216. 组合总和 III
78. 子集
90. 子集 II
401. 二进制手表
二维平面上使用回溯法
floodfill算法,一类经典问题(深度优先的遍历)
200. 岛屿数量
位移顺序是否有要求?
130. 被围绕的区域
417. 太平洋大西洋水流问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r6vd6upN-1650351333874)(resource/image/image_wTvTfZWdJJTMnVCFQLGLHF.png)]
回溯法是经典人工智能的基础
51. N 皇后
快速判断不合法的情况
竖向:col[i]表示第i列被占用
横纵坐标相加都为定值
对角线1∶2*n-1个(i +j)
横纵坐标相减
对角线2∶2*n-1个 (i- j+n- 1)
N皇后有很多优化思路
52. N皇后 II
37. 解数独
有大量的重复计算
记忆化搜索 - 自上向下的解决问题
动态规划 - 自下向上的解决问题
**动态规划:**将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CwEVFemJ-1650351333875)(resource/image/image_rBzboHcZV9g417FES67MJ5.png)]
70. 爬楼梯
120. 三角形最小路径和
64. 最小路径和
如果不是非负整数会怎样?上下左右移动都可以呢?
343. 整数拆分
重叠子问题
记忆化搜索
动态规划
**最优子结构:**通过求子问题的最优解,可以获得原问题的最优解。
279. 完全平方数
91. 解码方法
62. 不同路径
63. 不同路径 II
198. 打家劫舍
暴力解法:检查所有房子的组合,对每一个组合,检查是否有相邻的房子,如果没有,记录其价值。找最大值。O((2^n)*n)
依然存在重叠子问题(记忆化搜索、动态规划)
练习:使用新的状态定义,完成问题
状态就是定义了这个函数要做什么;状态的转移定义了这个函数怎么做
213. 打家劫舍 II
0-1背包问题更多变种
多重背包问题:每个物品不止1个,有num(i)个。
完全背包问题:每个物品可以无限使用。
多维费用背包问题:要考虑物品的体积和重量两个维度?
物品间加入更多约束:物品间可以互相排斥;也可以互相依赖
416. 分割等和子集
322. 零钱兑换
377. 组合总和 Ⅳ
注意:顺序性
474. 一和零
注意:什么叫组成?必须用完?还是有剩余就可以?
139. 单词拆分
494. 目标和
最长上升子序列
300. 最长递增子序列
注意1∶什么是子序列? 注意2∶什么是上升? 注意3:一个序列可能有多个最长上升子序列;但这个最长的长度只有1个。
暴力解法:选择所有的子序列进行判断。O((2^n)* n )
LIS问题的O(nlogn)解法
376. 摆动序列
更多关于动态规划
最长公共子序列(LCS)
练习:求解LCS问题(递归、记忆化搜索、自底向上的动态规划代码)
dijkstra单源最短路径算法也是动态规划
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rskv6Odv-1650351333876)(resource/image/image_tmdy8AkWL6H6K2MgJomHNc.png)]
动态规划给出具体解(反向)
455. 分发饼干
392. 判断子序列
贪心算法与动态规划的关系
435. 无重叠区间
先要排序,方便判断不重叠。
暴力解法︰找出所有子区间的组合,之后判断它不重叠。O((2^n) *n )
动态规划?
最长上升子序列
注意:每次选择中,每个区间的结尾很重要。结尾越小,留给了后面越大的空间,后面越有可能容纳更多区间
贪心算法
按照区间的结尾排序,每次选择结尾最早的,且和前一个区间不重叠的区间
贪心选择性质
如果无法使用贪心算法,举出反例即可。
如果无法举出反例,如何证明贪心算法的正确性? 反证法