递归
概念与特性 | 函数调⽤函数⾃身的编程⽅式叫做递归,调⽤为”递“,返回为”归“ |
三个条件 | 1. ⼀个问题的解可以分解为多个⼦问题的解; 2. 分解之后的⼦问题,除了数据规模不同,求解思路跟原问题相同; 3. 存在递归终⽌条件; |
编程技巧 | 1. 寻找将⼤问题分解为⼩问题求解的规律; 2. 找出递推公式和终⽌条件,将其直接翻译成代码; 3. 切记不要⼈⾁⼀层⼀层的递归; 换句话说,也就是:如果⼀个问题A可以分解为若⼲⼦问题B、C、D,我们可以假设⼦问题B、C、D已经解决,在此基础上思考如何解决问题A。 我们只需要思考问题A与⼦问题B、C、D两层之间的关系即可,不需要⼀层⼀层往下思考⼦问题与⼦⼦问题,⼦⼦问题与⼦⼦⼦问题之间的关系。 |
应⽤场景 | 递归是⼀种应⽤⾮常⼴泛编程技巧,很多数据结构和算法的编码实现都要 ⽤到递归,⽐如快排、归并排序、DFS(深度优先搜索算法)、⼆叉树遍历、回溯等; |
其他知识点 | 1. 避免堆栈溢出(限制调⽤层次;递归改为迭代;尾递归优化); 2. 避免重复计算(利⽤备忘录); |
掌握程度 | 1. 熟练编写斐波那契数列、全排列、⼋皇后、快速排序;归并排序、DFS、⼆叉树遍历、链表反转递归实现等; |
排序
概念与特性 | 1. 稳定性:如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变; 2. 原地:不额外申请⾮常量级的空间来临时存储排序数据;原地排序算法并不⼀定空间复杂度是O(1),空间复杂度是O(1)的排序算法⼀定是原地排序算法,⽐如快速排序是原地排序算法,但因为⽤到递归,函数调⽤栈会消耗⾮常量级的空间,所以,空间复杂度并⾮O(1),是O(logn)。 | |
O(n^2) | 冒泡排序 | 冒泡排序是稳定原地排序算法。 整个冒泡排序过程包含多遍冒泡操作。每次冒泡操作都会遍历整个数组,依次对相邻的元素进⾏⽐较,看是否满⾜⼤⼩关系要求,如果不满⾜,就将它们互换位置。⼀次冒泡操作会让⾄少⼀个元素移动到它应该在的位置,重复n次,就完成了n个数据的 排序⼯作。 |
插⼊排序 | 插⼊排序是稳定原地排序算法。⾸先,我们将数组中的数据分为两个区间,已排序区间和未排序区间。初始已排序区间只有⼀个元素,就是数组中的第⼀个元素。插⼊算法的核⼼思想是取未排序区间中的元素,在已排序区间中找到合适的插⼊位置将其插⼊,并保证已排序区间数据⼀直有序。重复这个过程,直到未排序区间中元素为空,算法结束。 | |
选择排序 | 选择排序算法是⾮稳定原地排序算法。其实现思路有点类似插⼊排序,也分已排序区间和未排序区间。 但不同点在于,选择排序算法每次会从未排序区间中,找到最⼩ 的元素,将其放到已排序区间的末尾。 | |
O(nlogn) | 快速排序 | 快速排序是⾮稳定原地排序算法。空间复杂度是O(logn)。 如果要排序数组中下标从p到r之间的⼀组数据,我们选择p到r之 间的任意⼀个数据作为pivot(分区点),然后,遍历p到r之间 的数据,将⼩于pivot的放到左边,将⼤于pivot的放到右边,将 pivot放到中间。经过这⼀步骤之后,p到r之间的数据就被分成 了三个部分。假设pivot现在所在位置的下标是q,那p到q-1之 间数据都⼩于pivot,中间是pivot,q+1到r之间的数据都⼤于 pivot。根据分治、递归的处理思想,我们递归排序下标从p到 q-1之间的数据和下标从q+1到r之间的数据,直到区间缩⼩为 1,就说明所有的数据都有序了。 递推公式:quickSort(p…r)=quickSort(p…q-1) & quickSort(q+1…r) |
归并排序 | 归并排序是稳定⾮原地排序算法。空间复杂度是O(n)。 如果要排序⼀个数组,我们先把数组从中间分成前后两部分,然后,对前后两部分分别排序,再将排好序的两部分合并在⼀起,这样整个数组就都有序了。递推公式:mergeSort(p…r)=merge(mergeSort(p…q), mergeSort(q+1… r)) | |
O(n) | 桶排序 | 桶排序,顾名思义,会⽤到“桶”,核⼼思想是将要排序的数据分到⼏个有序的桶⾥,每个桶⾥的数据再单独进⾏排序。桶内排完序之后,再把每个桶⾥的数据按照顺序依次取出,组成的序列就是有序的了。要排序的数据需要很容易就能划分成m个桶,并且,桶与桶之间 有着天然的⼤⼩顺序。这样每个桶内的数据都排完序之后,桶与桶之间的数据不需要再进⾏排序。 |
计数排序 | 实际上,计数排序是桶排序的⼀种特殊情况。当要排序的n个数据,所处的范围并不⼤的时候,⽐如最⼤值是k,我们就可以把数据划分成k个桶。每个桶内的数据值都是相同的,省掉了桶内排序的时间。 | |
基数排序 | 基数排序对要排序的数据也是有要求的,需要可以分割出独⽴的“位”来⽐较,⽽且位之间有递进的关系:如果a数据的⾼位⽐ b数据⼤,那剩下的低位就不⽤⽐了。除此之外,每⼀位的数 据范围不能太⼤,可以使⽤其他线性排序算法来排序,否则,基数排序的时间复杂度就⽆法做到O(n)了。 | |
应⽤场景 | ⼯程中的排序函数⼀般使⽤O(nlogn)的快排、归并或者堆排序作为主排序算 法,当数据规模较⼩时,转⽽选择使⽤更加简单的插⼊排序。 | |
其他知识点 | 为了避免快速排序时间复杂度退化为极端情况O(n^2),我们使⽤更加⾼级的 分区点选择⽅式,⽐如三数取中法、随机法等。 | |
掌握程度 | 1. 熟练掌握冒泡、插⼊、选择、快速、归并排序的原理、代码实现; 2. 熟练掌握快速、归并排序的时间和空间复杂度分析; 3. 掌握桶排序、计数排序、基数排序的原理 |
⼆分查找
概念与特性 | ⼆分查找针对的是⼀个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对⽐,将待查找的区间缩⼩为之前的⼀半,直到找到要查找的元素,或者区间被缩⼩为0。 |
操作与复杂度 | ⼆分查找的时间复杂度是O(logn) |
⼆分查找变体 | 变体⼀:查找第⼀个值等于给定值的元素 变体⼆:查找最后⼀个值等于给定值的元素 变体三:查找第⼀个⼤于等于给定值的元素 变体四:查找最后⼀个⼩于等于给定值的元素 |
掌握程度 | 熟练掌握⼆分查找、⼆分查找变体的代码实现 |
相关图片
参考链接
- 菜鸟教程