【LeetCode】快排-无序整数数组中找第k大的数(或者最小的k个数)
一个有代表性的题目:无序整数数组中找第k大的数,对快排进行优化。
这里先不说这个题目怎么解答,先仔细回顾回顾快排,掰开了揉碎了理解理解这个排序算法:时间复杂度、空间复杂度;什么情况下是复杂度最高的情况。
1.主要思想
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另一部分的所有数据要小,再按这种方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,使整个数据变成有序序列。
快排是冒泡排序的改进,改进点:冒泡排序每次只能交换相邻的两个元素,而快速排序是跳跃式的交换,交换的距离很大,因此总的比较和交换次数少了很多,速度也快了不少。
2.具体排序例子
步骤:
- 要找一个数字作为基准数(这只是个专用名词)。为了方便,我们一般选择第 1 个数字作为基准数(其实选择第几个并没有关系)。
- 我们需要把这个待排序的数列中小于基准数的元素移动到待排序的数列的左边,把大于基准数的元素移动到待排序的数列的右边。这时,左右两个分区的元素就相对有序了;
- 接着把两个分区的元素分别按照上面两种方法继续对每个分区找出基准数,然后移动,直到各个分区只有一个数时为止。这是典型的分治思想,即分治法。
举个例子,放个图理解理解:
以 47、29、71、99、78、19、24 的待排序的数列为例进行排序,为了方便区分两个 47,我们对后面的 47 增加一个下画线,即待排序的数列为 47、29、71、99、78、19、24。
言而总之:小于基准数的,放在左边,大于基准数的,放在右边,最后,基准数放在二者中间即可。
代码:
public class Sort_quick_sort {public void quick(int[] src, int begin, int end) {if (begin < end) {//基准数int key = src[begin];int i = begin;int j = end;while (i < j){//如果右边大于基准数,j-- while(i < j && src[j] > key){j--;}//上面循环结束,说明右边不大于基准数了,换位置if (i < j){swap(src, i, j);i++;}//如果左边的小于基准,i++ while (i < j && src[i] < key) {i++;}//上面循环结束,说明左边不小于基准数了,换位置if (i < j){swap(src, i, j);j--;}}//当i== j的时候,基准数停留在了它应该在的位置,分而治之的递归下去quick(src, begin, i - 1);quick(src, i + 1, end);}}public void swap(int[] arr, int i, int j){int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static void main(String args[]) {Sort_quick_sort obj = new Sort_quick_sort();int[] num = {2, 7, 11, 15, 1, 0, 0,15};obj.quick(num, 0, num.length - 1);for (int n: num){System.out.print(n+ "\n");}}}
2.复杂度
时间复杂度
快速排序在最坏情况下的同冒泡排序,是 O(n2),
每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序),冒泡排序的时间复杂度:T[n] = n * (n-1) = n^2 + n。
数列的平均时间复杂度是 O(nlogn).
空间复杂度
从代码来看,仅定义了几个变量,占用常数空间,使用的空间是O(1)的,也就是个常数级;而真正消耗空间的就是递归调用了,因为每次递归就要保持一些数据,所以空间复杂度不是O(1)。
在最差的情况下,退化为冒泡排序的情况,若每次只完成了一个元素,那么空间复杂度为 O(n)。
快速排序只是使用数组原本的空间进行排序,所以所占用的空间应该是常量级的,但是由于每次划分之后是递归调用,所以递归调用在运行的过程中会消耗一定的空间,在一般情况下的空间复杂度为 O(logn)。
稳定性:
快速排序是一个不稳定的算法,在经过排序之后,可能会对相同值的元素的相对位置造成改变。快速排序基本上被认为是相同数量级的所有排序算法中,平均性能最好的。
思考:真正理解一个东西,是具备举一反三的能力,如果不能,需要再去理解理解了。当然,在说时候,也不要紧张,容易大脑一片空白,质疑自己[
【LeetCode】快排-无序整数数组中找第k大的数(或者最小的k个数)相关推荐
- C语言(CED)输出前k大的数(分治法/局部快速排序):给定一个数组,统计前k大的数并且把这k个数从大到小输出。
)输出前k大的数(分治法/局部快速排序):给定一个数组,统计前k大的数并且把这k个数从大到小输出. [输入] 第一行包含一个整数n,表示数组的大小. 第二行包含n个整数,表示数组的元素,整数之间以一个 ...
- 【c语言】在一个一维整数组中找出其中最大的数及其下标
//在一个一维整型数组中找出其中最大的数及其下标 #include <stdio.h> #define N 10 int fun(int* a, int* b, int n) {int* ...
- LeetCode 154 在有序旋转数组中找最小-2
Follow up for "Find Minimum in Rotated Sorted Array": What if duplicates are allowed? Woul ...
- 面试题:从n个数中找出第K大的数
参考https://blog.csdn.net/orangefly0214/article/details/84997668的思路 从有n个元素的乱序数组中找出第k大的元素 方法1:基于冒泡排序和简单 ...
- java查找第k大的数字_查找数组中第k大的数
问题: 查找出一给定数组中第k大的数.例如[3,2,7,1,8,9,6,5,4],第1大的数是9,第2大的数是8-- 思考:1. 直接从大到小排序,排好序后,第k大的数就是arr[k-1]. 2. ...
- 【Leetcode】两个有序数组,求第k大的数
双指针: def func(num1,num2,k):i,j,n = 0,0,0while i<len(num1) or j<len(num2):n += 1if i<len(num ...
- java寻找数组中第k大的数
快速排序思想,先找数组第k小的数,当执行一次partition函数找到index下标时,index左边的数比arr[index]小,右边的数比arr[index]大 public class Test ...
- NC88-寻找第K大的数
描述 有一个整数数组,请你根据快速排序的思路,找出数组中第K 大的数. 给定一个整数数组 ,同时给定它的大小n和要找的K ,请返回第 K大的数(包括重复的元素,不用去重),保证答案存在. 要求时间复杂 ...
- 无序数组中找第K大的数
类快排算法 leetcode215 由于只要求找出第k大的数,没必要将数组中所有值都排序. 典型解法:快速排序分组. 在数组中找到第k大的元素 取基准元素,将元素分为两个集合,一个集合元素比基准小,另 ...
最新文章
- 皮一皮:谈恋爱一定要谨慎...
- Unity Standard Assets 简介之 Cameras
- etcd - 一个分布式一致性键值存储系统
- android像素鸟,像素鸟Flappy Bird
- 解决ifconfig没有网卡问题
- 笔记 3 文件的特殊属性,权限
- 解决PyCharm出现无法连接Docker的问题
- spring 事务传播机制总结
- 计算标准累积正态分布_神说要有正态分布,于是就有了正态分布。
- average函数python_在Python3 numpy中mean和average的区别详解
- 深度学习笔记——情感分析
- 优酷盗播引版权方围攻 视频大佬陷孤军奋战困局
- MCU-LCD屏与RGB-LCD屏的区别?
- 感觉自己成长慢,单点突破可以让你成长快10倍
- IP-guard屏幕监控,违规操作全记录
- 转载 Fluent中的压力分类
- 如何培养新人总结_如何将一名新员工快速带入新岗位?
- 如何制作使用lib和dll
- Twig模版语言入门
- 数字电路实验四:智力抢答器预实验报告