数据结构视频讲解-第一课

复杂度问题

评价一个算法首先看算法的时间复杂度。
二分法搜索的时间复杂度为O( log ⁡ 2 N \log_2 N log2N),外排法的时间复杂度为O(N+M)。
简单的几个排序方法:冒泡排序,选择排序,插入排序。冒泡排序和选择排序的时间复杂度都是严格的O( N 2 N^2 N2),插入排序在最坏情况下时间复杂度为O( N 2 N^2 N2),它与实际的数据状况有关(当数据已经有序时不用执行交换)。

递归行为

递归就是系统不断地自动压栈的过程,因此任何递归行为都可以改为非递归。
计算递归行为的时间复杂度的master公式:
数据结构视频讲解-第一课_第1张图片
注意:master公式只适用于分解成子问题的规模相同的情况。

归并排序可以写成:
T(N)=2 T( N 2 \frac{N}{2} 2N)+O(N)
归并排序是先分解为子问题,然后用外排的方法聚合merge两个子问题。
思想:分治问题。

数据结构视频讲解-第一课_第2张图片
组内比较的次数不会被浪费,每次Merge都是在跨组比较。

快速排序

荷兰国旗问题
经典快速排序
利用荷兰国旗问题来改进后的快速排序
随机快速排序:时间复杂度O( n log ⁡ n n\log n nlogn),空间复杂度O( log ⁡ n \log n logn)用来记录断点位置。

堆结构很重要!
堆排序

排序的稳定性

01标准的划分问题在O(1)空间复杂度,O(N)时间复杂度情况下不可能做到稳定。(要做到稳定的方法已经超纲了)。
如果可以的话快排的partition过程就可以做到稳定性了。

非比较排序

桶排序
例题:给定一个数组,求如果排序之后,相邻两个数的最大差值,要求时间复杂度O(n),且要求不能用非基于比较的排序。

栈,队列

  1. 用数组实现固定长度的栈和队列行为。
    实现栈:用index表示将要进来和弹出的数的index。
    实现队列:用start,end,size;end指向将要进来的数的index;start指向将要弹出的数index;size表示队列中的数的个数;用size解耦start和end。
  2. 实现栈结构的pop,push,getMin,只能用时间复杂度O(1).
    方法:采用两个栈,一个栈Data存放正常的数据,一个栈Min存放当前数组长度下的最小值,Min栈中重复比较栈顶和当前数,压入其中的更小值。
  3. 如何仅用队列结构实现栈?如何仅用栈结构实现队列?
    用两个队列data,help实现栈;
    用两个栈push,pop实现队列;push栈一次要倒完,pop栈有数的时候push栈不要倒入。

矩阵

宏观把控思想
转圈打印矩阵;(每次打印矩阵的最外边一圈,给出左上角和右下角就可以打印一圈)
“之”字形打印矩阵;(每次给出一个对角线的起点和终点,找出起点和终点的移动规则,然后根据起点和终点打印)
在行和列都排好的矩阵中查找数;(根据数据状况,找出复杂度最低的解。)
降低复杂度,找到最优解一般就是两种方法:1.利用数据状况找到优化的方法;2.根据问题的问法来找到优化方法。

链表

链表问题在笔试和面试过程中可以遵循不同的思路:笔试中可以利用哈希表增加空间复杂度,力求代码简单易写即可;面试中要尽量降低空间复杂度,展示自己的能力。
经典问题:
1.判断一个链表是不是回文。(代码00:48:22)
笔试中直接将这个链表中的数入栈,然后比较栈和链表中的数即可;
面试中,用一个快指针和一个满指针,找到链表的中间位置,然后反转后部分的链表,找到尾部指针P2,然后从头指针head和尾指针P2开始逐步对比链表数值。
2.将单向链表按某值划分成左边小、中间相等、右边大的形式。
遍历一遍,找到第一个小于,等于,大于该值的结点,再遍历一遍,将链表中的结点分为以上三类,分别接在以上三个结点后面,最后连接这三个子链表。
3.复制含有随机指针节点的链表。
笔试中,可使用哈希表,创建原始每个结点的复制结点并创建对应关系;
面试中,将每个结点的复制结点接在该结点后面,来建立等效于哈希表带来的一种对应关系。(代码1:18:19)
4.两个单链表相交的一系列问题
分两步:1.判断两个单链表是否有环;2.若均无环,则设计无环的判断思路,若均有环,则设计有环的判断思路,若一个有环一个无环,则不相交。
如何判断一个链表是否有环,如果有环,则返回第一个进环的结点?
设置两个指针,一个快指针一次走两步,一个满指针一次走一步,从头结点走起,当两个指针追上时说明有环,若快指针指向空说明无环。两个指针追上之后,选择一个指针从头走起,另一个指针从追上点走起,第一次相交的点就是入环点。
若均无环,
若均有环,有三种拓扑结构。。。

二叉树

三种遍历方法

哈希函数与哈希表

哈希函数的几个特征:
1.输入域无穷;
2.输出域有限;
3.相同的输入必有相同的输出;必有不同的输入产生相同的输出。
4.输出离散均匀分布在输出域上。

哈希表
哈希表是通过哈希函数的映射关系构造的,通过对原始结点的key做hashcode得到编码后的结果mod m得到余数作为该节点的地址。
哈希表的作用:
1)实现O(1)复杂度的增删改查,例如设计RandomPool结构。(这里注意补洞)
2)大量文本中查找chogndu。
具体方法是:如果可以同时使用m个机器,对每个文件进行哈希编码得到hashcode,将hashcode对m取余得到机器编号,将这个文件放在这个机器中,这样就可以达到同样的文件来到同一个机器中,并且文件几乎均匀分布在每个机器中,因此实现并行化的查找。
(大数据题目中一般都会使用哈希函数)

布隆过滤器
布隆过滤器(Bloom Filter)的核心实现是一个超大的位数组和几个哈希函数。
布隆过滤器添加元素:
将要添加的元素给k个哈希函数
得到对应于位数组上的k个位置
将这k个位置设为1
布隆过滤器查询元素:
将要查询的元素给k个哈希函数
得到对应于位数组上的k个位置
如果k个位置有一个为0,则肯定不在集合中
如果k个位置全部为1,则可能在集合中
应用:如果一个公司有一个包含100亿个url黑名单的库,如何判断一个url是否在库中?
如果使用hashmap来做,其所需要的内存很大(因为要存储这100亿个url)。如果允许查找有失误的话,布隆过滤器就派上用场了,它分别把这100亿个url做哈希编码来映射,然后用一个新的url来查询是否存在于这个集合中,查询可能存在失误率p.
设允许的失误率为P,所有文件个数为n,需要的bit位数为m,则 m = − n × ln ⁡ p ( ln ⁡ 2 ) 2 m=-\frac{n\times \ln p}{(\ln 2)^2} m=(ln2)2n×lnpbit;
哈希函数的个数 k = ln ⁡ 2 × m n k=\ln 2\times \frac{m}{n} k=ln2×nm,m和k均向上取整之后的失误率调整为**。

一致性哈希
为了解决扩容时出现的大量计算量,而将m化为环,将服务器分布在环上,顺时针在服务器i之前的数据属于i。
用虚拟结点技术做到每个机器中承载的计算量大致均匀。
(现在的服务器抗压一般都使用一致性哈希。)

并查集
实现两个功能:
1.非常快地检查两个元素是否在一个集合中IsSameSet;2.合并两个元素所在的集合Union。
要求:初始化时所有的元素都给这个函数。
实现过程:
1)初始化,每个结点都自成一个集合,并且用hashmap构造初始的fathermap和sizemap;
2)实现基本操作findHead,注意查找的过程中要将整个查找过程打扁平;
3)实现并查集的两个功能。
岛问题有两种解法,第一种方法对小矩阵而言,用Infect感染函数,对所有1经过的地方的上下左右都感染到(改为2),最后判断遇到多少次1;2.对大矩阵进行划分为小矩阵时,处理小矩阵之间的边界问题,使用并查集来检查。可以做到并行计算。

当查询和合并次数达到O(n)时,平均操作复杂度为O(1).

前缀树

贪心策略

贪心策略都可以用对数器检验。
要证明这个贪心策略成立是比较难的。
1.经常使用堆结构,因为堆就是按照某种标准构造的结构;例如哈夫曼编码中使用最小堆。
实例:1.哈夫曼编码;2.IPO(项目和利润);3.字符串拼接;4.安排项目

暴力递归到动态规划

递归过程中有重复状态,且这种状态与到达它的路径无关,则暴力递归可以改为动态规划。

你可能感兴趣的:(数据结构)