玩转算法面试笔记


title: 玩转算法面试笔记

主要分章节记录了LeetCode的题,看题目的话可以从第二章开始

1、聊聊算法面试

1.1、对一组数据进行排序,你会怎么做呢

1、这组数据有什么样的特征?

  • 有没有可能包含有大量重复的元素?

    如果有这种可能的话,三路快排是更好地选择。(Java种快排的基本实现就是使用三路快排)

  • 是否大部分数据距离它正确的位置很近?是否近乎有序?

    如果是这样的话,插入排序是更好地选择。(如对银行的业务按照业务发生的时间进行排序,大多数业务先发生也先结束,少数处理的业务先发生但是处理时间较长后结束)

  • 是否数据的取值范围非常有限?比如对学生成绩排序。

    如果是这样的话,计数排序是更好地选择。

2、对排序有什么额外的要求?

  • 是否需要稳定排序?

    如果是的话,归并排序是更好地选择。

3、数据的存储状况是怎样的?

注:快排非常依赖于数组的随机存取

  • 是否是使用链表存储的?

    如果是的话,归并排序是更好地选择。

  • 数据的大小是否可以装载在内存里?

    数据量很大,或者内存很小,不足以装载在内存里,需要使用外排序算法。

在很多情况下,基础的普通的快排都不是最优的选择,甚至在一些情况下,快排根本是不适用的,在工作中真实的处理一个问题,就需要考虑各种各样的条件。关键在于你所表达出的解决问题的思路。

1.2、算法面试没有那么难

并不需要啃完一本《算法导论》,强调理论证明。

看书的时候重思想,轻理论

高级数据结构和算法面试提及的概率很低(第一轮)

  • 红黑树

  • 计算集和

  • B-Tree

  • 斐波那契堆

  • 数论

  • FFT

那么算法面试的准备范围是什么?

不要轻视基础算法和数据结构,而是关注“有意思”的题目。

  • 各种排序算法

  • 基础的数据结构和算法实现:堆、二叉树、图…

  • 基础数据结构的使用:链表、栈、队列、哈希表、图、trie、并差集…

  • 基础算法:深度优先、广度优先、二分查找、递归…

  • 基础算法思想:递归、分治、回溯搜索、贪心、动态规划…

在学习和实践做题之间要掌握平衡。不要只关注于题目的正确与否(只刷题),更要注重其中的算法思想。

1.3、解决算法面试问题的整体思路

  1. 注意题目中的条件。

    • 比如给定一个有序数据…

      是不是能用二分查找法来进行相关的搜索

    • 有一些题目中的条件本质是暗示

      • 设计一个O(nlogn)的算法

        • 八成离不开分治法,也就是在一棵搜索树中完成任务

        • 这个O(nlogn)是不是对一个数组排序的时间复杂度,我们是不是要先对整个数组进行排序,然后看有没有可能在O(n)或者O(logn)的时间复杂度下完成其他的任务

      • 无需考虑额外的空间

        是不是需要开辟额外的空间,用空间换时间

      • 数据规模大概是10000

        设计O(n2)的算法就可以解决这个问题,这是因为对于O(n2)的算法完全可以处理百万级甚至是千万级的数据

  2. 当没有思路的时候,给自己几个简单的测试用例,试验一下;

  3. 不要忽视暴力解法,暴力解法通常是思考的起点。

  4. **优化算法。**遍历常见的算法思路,遍历常见的数据结构,空间和时间的交换(哈希表),对数据进行预处理(排序)。在瓶颈处寻找答案:O(nlogn)+ O(n^2) ; O(n^3)。

实际编写问题

1、极端条件的判断。数组为空,字符串为空?数量为0?指针为NULL等等

2、变量名最好具有语义

3、代码的模块化,复用性等等

2、数组常见问题

对撞指针

  • 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”

    滑动窗口

数组中的问题其实最常见

排序︰选择排序;插入排序;归并排序;快速排序

查找:二分查找法

数据结构︰栈;队列;堆

如何写出正确的程序

明确变量的含义

循环不变量

小数据量调试

大数据量测试

3、查找表相关问题

  • 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. 回旋镖的数量

    • 暴力解法:O(n^3)
  • 149. 直线上最多的点数

    点坐标的范围(防止越界)?点坐标的表示(整数?浮点数?浮点误差?)

  • 219. 存在重复元素 II

    • 暴力解法:O(n^2)

    • 滑动窗口 + 查找表

  • 217. 存在重复元素

  • 220. 存在重复元素 III

4、在链表中穿针引线

  • 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)的空间复杂度解决问题?

5、栈,队列,优先队列

栈的基础使用

  • 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个升序链表

6、天然递归结构_二叉树

简单树形与递归

  • 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. 二叉树的最近公共祖先

7、递归和回溯法

递归调用的一个重要特征–要返回(回溯)

回溯法是暴力解法的一个主要实现手段

树形问题

  • 17. 电话号码的字母组合

    字符串的合法性;空字符串;多个解的顺序

    时间复杂度∶3^n = O(2^n)

  • 93. 复原 IP 地址

  • 131. 分割回文串

用回溯解决排列问题

  • 46. 全排列

  • 47. 全排列 II

用回溯解决组合问题

  • 77. 组合

    优化:取4时是没有必要的

  • 39. 组合总和

  • 40. 组合总和 II

  • 216. 组合总和 III

  • 78. 子集

  • 90. 子集 II

  • 401. 二进制手表

二维平面上使用回溯法

  • 79. 单词搜索

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. 解数独

8、解开动态规划的神秘面纱

有大量的重复计算

记忆化搜索 - 自上向下的解决问题

动态规划 - 自下向上的解决问题

**动态规划:**将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CwEVFemJ-1650351333875)(resource/image/image_rBzboHcZV9g417FES67MJ5.png)]

  • 70. 爬楼梯

  • 120. 三角形最小路径和

  • 64. 最小路径和

    如果不是非负整数会怎样?上下左右移动都可以呢?

  • 343. 整数拆分

    • 暴力解法:回溯遍历将一个数做分割的所有可能性。O(2^n)

    重叠子问题

    • 记忆化搜索

    • 动态规划

    **最优子结构:**通过求子问题的最优解,可以获得原问题的最优解。

  • 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)]

动态规划给出具体解(反向)

9、贪心算法

  • 455. 分发饼干

  • 392. 判断子序列

贪心算法与动态规划的关系

  • 435. 无重叠区间

    先要排序,方便判断不重叠。

    • 暴力解法︰找出所有子区间的组合,之后判断它不重叠。O((2^n) *n )

    • 动态规划?

      最长上升子序列

    注意:每次选择中,每个区间的结尾很重要。结尾越小,留给了后面越大的空间,后面越有可能容纳更多区间

    • 贪心算法

      按照区间的结尾排序,每次选择结尾最早的,且和前一个区间不重叠的区间

贪心选择性质

如果无法使用贪心算法,举出反例即可。

如果无法举出反例,如何证明贪心算法的正确性? 反证法

你可能感兴趣的:(数据结构,算法,leetcode)