经典算法题汇总

链表

  1. 链表第一个公共节点:1) 利用栈先进后出,用两个栈对两个链表从头至尾遍历,那么栈顶就为链表的尾节点,依次弹出两个栈,直到弹出的元素不一样时,前一个相同的即为第一个公共节点. 2)分别遍历一次两个链表,算出长度差L,让长的链表的指针先走L步,然后两个指针同时移动,那么第一次指向同样节点的即为公共节点

  2. 判断是否存在环:两个指针,每次慢指针走1步,快指针走2步,如果快的最后追上慢的,那么有环

  3. 判断环的长度:从快指针追上慢指针的那个节点开始(此时一定是在环内),再让快慢指针同时移动,第二次快指针追上慢指针时,记录两个指针走过的步数,差值为环的长度

  4. 寻找入环口:一个指针从第一次快指针追上慢指针的那个节点开始,一个指针从链表头开始,两个指针同时移动,每次移动一步,如果两个指针的下一个节点相同,那么那个节点就是入环口

  5. 给定单链表节点,删除此节点: 把后面一个节点内容复制到此节点,然后把此节点的p.next指针指向p.next.next即可

  6. 链表的倒数第k个节点: 1)前后指针,后指针先走k步,然后两个指针同时后移,直到后指针指向尾节点,那么前指针即为所求. 2) 用栈储存链表,然后弹出节点,弹出的第k个即为所求

树:

  1. 根据二叉树前序,中序还原二叉树:前序的特点是根节点在序列第一位,然后在中序中找到这个根节点,左边的就是左子树所有的节点,右边就是右子树所有的节点,然后递归构造左边的序列和右边的序列

  1. 两个栈实现队列: 栈1为主栈,push函数实现:直接押入栈1。pop函数:判断栈2是否为空,若是,把栈1的元素pop再push进去,直到栈1空,然后把栈顶元素pop;若非空,则直接pop即可。

  2. 两个队列实现栈:push方法正常入队deque1,当要pop出最后一个进去的元素时,将前面的元素出队并入队在deque2中,然后把最后一个元素出队。如果要再出队一个元素,那么就把deque2的前面元素出队再入队至deque1中,保持两个队列一个为空,插入元素时插入非空的队列

数组

  1. 数组包含1000w,找到所有的两个数组合,使两个数的和为给定的n: 1) 先排序,然后计算前后指针的和,若和大于n,则后指针迁移一个,若和小于n,前指针后移,若相等则找到一个组合,时间O(nlogn), 空间O(1),2) 使用一个HashSet储存n与数组每个值的差值,从头开始,将每个差值储存进HashSet,判断当前的值在HashSet是否存在,若存在则找到一对,时间O(N), 空间O(N)

  2. 数组中出现次数超过一半的数字: 我们有时间复杂度为O(n)的算法得到数组中任意第k大的数字:随机找一个数,小的放左边,大的放右边,如果这个数的下标刚好为n/2,那么这个数就是中位数,即为所求;若这个数下标小于n/2, 那么中位数在右侧,反之则相反

  3. 调整数组顺序使奇数位于偶数前面:前后指针,若前指针为偶数,后指针为奇数则交换;若前后都为奇数,前指针后移,若前后都为偶数,则后指针前移;若前奇后偶,前后指针同时移动,直到前指针与后指针相遇

其他

LRU缓存策略:最近最少使用算法,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。链表实现:新数据插入链表头部,每当缓存命中时,将数据移到链表头部,链表满的时候,将链表尾部丢弃

随机游走: 一个人在原点,向左右走的概率各为p和1-p,假设走了N步,求他最后位于距离原点X距离的期望。解:向左共走了a=(N-X)/2步,向右共走了b=(N+X)/2步,根据二项分布可得期望 E=CaNpa(1p)b E = C N a p a ( 1 − p ) b

100G数据排序,内存限制2G

外部排序:将数据拆分为50份文件,每份文件大小2G,对每份文件导入内存进行内部排序(归并排序等),得到50份有序的文件,再比较这50份文件里的第一个数,最小的数即为整个100G数据中最小的,然后不断归并,最终能得到100G有序数据

  • 优化1:利用流水线技术。将每份文件排序过程分为,读取数据→排序数据→写数据,3个过程并行处理,例如在向文件1写入已排序数据的过程中,同时排序文件2数据和读入文件3数据。注意此时每个文件划分大小应为1/3G,因为三个文件的数据会同时加载进2G内存。
  • 优化2:在最后的归并过程中,每次在寻找当前最小值时,需要扫描50个文件的头数据,找到最小值,平均复杂度O(n),这里n=50。因此,我们可以维护一个大小为n的最小堆,每次取出堆顶元素(最小值)O(1),并插入取出元素对应文件中的下一个数据,这个插入过程只需要O(logn),整个空间复杂度O(n)

从两个大文件里找相同的QQ号

桶排序:这里考虑到内存限制,无法同时读入两个大文件到内存里,那么我们可以按照散列值将每个QQ号映射到小文件中,然后在对应的小文件中寻找相同的QQ号。具体来说,扫描文件A和B,分别将两个大文件中的每个QQ号用hash(QQ)%1000映射到两组小文件里,每组小文件个数为1000,例如文件编号为A1…A1000和B1…B1000。由于相同的QQ号具有相同的散列值,因此对1000的取模也相同,我们只需在对应编号的文件里寻找即可,例如A1和B1,A2和B2。对于A1和B1,我们可以先将A1所有的QQ号都导入hashSet,然后对每个B1中的QQ号用hasCode函数来判断重复元素,也就是相同的QQ号。

你可能感兴趣的:(算法题)