排序
这里只简单的放上相应的模板,具体的算法思想见我另外一篇文章 《十大内部排序》
细节
分类
复杂度
补充:
在这里要说明的是,这个图里的快排空间复杂度错了,快排的平均空间复杂度应该是 O(logn),就是栈的深度,但是最差的情况下,比如全是倒序,则空间复杂度为栈深度 O(n)。归并排序每次递归需要用到一个辅助表,长度与待排序的表相等,虽然递归次数是O(log2n),但每次递归都会释放掉所占的辅助空间,所以下次递归的栈空间和辅助空间与这部分释放的空间就不相关了,因而空间复杂度还是 O(n)。
稳定性
- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
- 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
- 不稳定排序算法:谐音记忆法:快(快排) 些(希尔)选(选择)对(堆)。
- 总共4个不稳定,6个稳定。
面试点
jdk层面实现的sort总共是两类,一个是 Arrays.sort(), Collections.sort():
Arrays.sort()
- 如果数组内元素是基本数据类型,最主要采用的是双轴快速排序「其实就是三路快排一模一样的思路,只不过三路快排中间是 = pivot1,而双轴快速排序是(pivot1,pivot2),具体戳链接:https://www.cnblogs.com/nullzx/p/5880191.html 。
总结一下:数组长度小于47的时候是用直接插入算法,大于47并且小于286是采用双轴快速排序,大于286如果连续性好「也就是元素大多有序,有一个flag专门用来记录数组元素的升降次数,代表这个数组的连续性」采用的是归并排序,否则还是依旧采用双轴快速排序。
如果数组内元素是对象,采用的是TimSort.sort(),跟 Collections.sort()一样,都是采用的这个函数,这是归并排序算法和插入排序的结合。
Collections.sort(),采用 TimSort.sort()。
TimSort.sort() 大概原理:
- 当待排序元素小于32个时,采用二分插入排序,是插入排序的一种改进,可以减少插入排序比较的次数。当找到插入位置时,直接利用System.copy()函数即可。
- 当待排序元素大于等于32个时,进行归并排序(和传统的归并不一样),首先将排序元素分区,每个分区的大小区间为[16,32),然后依次对每个分区进行排序(具体实现依然是二分插入排序),排完序的分区压入栈(准确的说不是栈,而是一个数组,用来记录排序好的分区),当栈内的分区数满足条件时,进行分区合并,合并为一个更大的分区,当栈中只剩一个分区时,排序完成。
模板
交换排序之冒泡
1 | public class BubbleSort { |
交换排序之快排
1 | public static void main(String[] args) { |
交换排序之三路快排
1 | private static void quickSortByThreeWays(int[] nums, int left, int right) { |
插入排序之直接插入排序
1 | /** |
插入排序之希尔排序
1 | /** |
选择排序之简单选择排序
1 | /** |
选择排序之堆排序
1 | /** |
二路归并排序
1 | /** |
计数排序
1 | /** |
桶排序
1 | public class BucketSort { |
基数排序
1 | /** 基数排序 |
二叉树遍历
这里只提供二叉树遍历模板,具体有关二叉树的内容可以移步我的另外一篇文章:二叉树专题总结
前序
递归
1 | class Solution { |
非递归
1 | // 1.1 非递归先序 |
中序
递归
1 | class Solution { |
非递归
1 | // 2. 中序非递归 |
后序
递归
1 | class Solution { |
非递归
1 | //3. 后序非递归 左右根 反过来讲就是 根右左 |
层序
递归
1 | public List<List<Integer>> levelOrder(Node root) { |
非递归
1 | //4.1 层序遍历 |
二分
面试的时候经常碰到二分,比如求根号n,求最左侧target的下标,求翻转后的有序数组对应的最左侧target下标等等。
模板
左闭右开
1 | public class binarySearch { |
左闭右闭
1 | package 二分查找; |
相关题目
根号n
1 | package 练手算法; |
34. 在排序数组中查找元素的第一个和最后一个位置
题目
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
代码
1 | class Solution { |
33. 搜索旋转排序数组
题目
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
代码
1 | class Solution { |
81. 搜索旋转排序数组 II
在上面的基础上,去除不可重复,这里的数组中的元素包含了可重复的元素,同时加大难度,要求找出第左侧的target的下标「这个我不会 」。
1 | class Solution { |
287. 寻找重复数
题目
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
代码
1 | class Solution { |