title: 玩转算法面试笔记
主要分章节记录了LeetCode的题,看题目的话可以从第二章开始
1、聊聊算法面试
1.1、对一组数据进行排序,你会怎么做呢
1、这组数据有什么样的特征?
-
有没有可能包含有大量重复的元素?
如果有这种可能的话,三路快排是更好地选择。(Java种快排的基本实现就是使用三路快排)
-
是否大部分数据距离它正确的位置很近?是否近乎有序?
如果是这样的话,插入排序是更好地选择。(如对银行的业务按照业务发生的时间进行排序,大多数业务先发生也先结束,少数处理的业务先发生但是处理时间较长后结束)
-
是否数据的取值范围非常有限?比如对学生成绩排序。
如果是这样的话,计数排序是更好地选择。
2、对排序有什么额外的要求?
-
是否需要稳定排序?
如果是的话,归并排序是更好地选择。
3、数据的存储状况是怎样的?
注:快排非常依赖于数组的随机存取
-
是否是使用链表存储的?
如果是的话,归并排序是更好地选择。
-
数据的大小是否可以装载在内存里?
数据量很大,或者内存很小,不足以装载在内存里,需要使用外排序算法。
在很多情况下,基础的普通的快排都不是最优的选择,甚至在一些情况下,快排根本是不适用的,在工作中真实的处理一个问题,就需要考虑各种各样的条件。关键在于你所表达出的解决问题的思路。
1.2、算法面试没有那么难
并不需要啃完一本《算法导论》,强调理论证明。
看书的时候重思想,轻理论
高级数据结构和算法面试提及的概率很低(第一轮)
-
红黑树
-
计算集和
-
B-Tree
-
斐波那契堆
-
数论
-
FFT
那么算法面试的准备范围是什么?
不要轻视基础算法和数据结构,而是关注“有意思”的题目。
-
各种排序算法
-
基础的数据结构和算法实现:堆、二叉树、图…
-
基础数据结构的使用:链表、栈、队列、哈希表、图、trie、并差集…
-
基础算法:深度优先、广度优先、二分查找、递归…
-
基础算法思想:递归、分治、回溯搜索、贪心、动态规划…
在学习和实践做题之间要掌握平衡。不要只关注于题目的正确与否(只刷题),更要注重其中的算法思想。
1.3、解决算法面试问题的整体思路
-
注意题目中的条件。
-
比如给定一个有序数据…
是不是能用二分查找法来进行相关的搜索
-
有一些题目中的条件本质是暗示
-
设计一个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、代码的模块化,复用性等等
2、数组常见问题
对撞指针
-
-
非原地
-
原地
-
k - [0…k)中保存所有当前遍历过的非0元素
-
将非0元素与0元素进行交换位置
-
优化:如果所有元素都是0,就不需要交换——增加一个判断
-
-
-
如何定义删除?从数组中去除?还是放在数组末尾?剩余元素的排列是否要保证原有的相对顺序?是否有空间复杂度的要求? O(1)
-
-
计数排序
-
三路快排
-
-
整数序列不一定有序(利用快排partition中,将pivot放置在了其正确的位置上的性质)
-
该题保证有解且唯一一个解。
如果没有解怎样?保证有解;如果有多个解怎样?返回任意解
-
最直接的思考:暴力解法(超时)。双层遍历,O(n^2)
暴力解法没有充分利用原数组的性质――有序
-
有序?二分搜索?
-
对撞指针
-
-
对于字符串常见的问题:空字符串如何看?字符的定义?大小写问题?
-
类似:翻转一个数组
-
这里元音不包含y
-
对撞指针
-
什么叫子数组(不要求连续,该题说的连续子数组);如果没有解怎么办?该题要求最短的连续子数组的长度,因此没有解就返回0(但如果要求最短的连续子数组,就有可能有多个解,那如果有多个解是只返回一个解还是返回所有解,返回一个解的话有没有特殊限定,返回所有解的话顺序是怎么样的)
-
暴力解
遍历所有的连续子数组[i.….j]
计算其和sum,验证sum &
-