NC88 寻找第K大

描述
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。

给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度 O(nlogn)O(nlogn),空间复杂度 O(1)O(1)
数据范围:0 <=n <= 1000, 0<K<n, 数组中每个元素满足 0<=val<=10000000。

示例1:
输入:[1,3,5,2,2],5,3
返回值:2
示例2
输入:[10,10,9,9,8,7,5,6,4,3,4,2],12,3
返回值:9
说明:去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9。

思想:
利用快排将数组先排序,排序之后,将第K大的取出即可。
快排的思想:
先从数列中取出一个数作为基准数(通常取第一个数)。
分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
再对左右区间重复第二步,直到各区间只有一个数。
快排的时间复杂度:O(nlogn)
需要注意的地方:
1)快排实质上是一个分治的思想,所以需要用到递归,递归的出口是left和right一致时,不需要再次排序,直接返回数组即可。
2)快排为了找到当前基准数的正确位置,需要用到两个游标 i 和 j,分别从两边开始找比基准值大和小的值,这里需要注意,如果选择的基准是最左测,这时需要先动j,即选从最右边选择到比基准值小的,因为选动的那个确定了截止范围,因为后面需要找到 i 和 j 相遇位置和基准数换,这个位置所在的数一定是要比基准数小的,因为基准数在最左测;同样的,要是选择最右侧的值作为基准值就要选择左边的i先动。
主要代码如下:

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param a int整型一维数组 
# @param n int整型 
# @param K int整型 
# @return int整型
#
class Solution:
    def findKth(self , a: List[int], n: int, K: int) -> int:
        self.kp(a, 0, n-1)  # 将数组a进行快排
        return a[n-K]       # 返回第K大的数
    
    
    def kp(self, a: List[int], left : int, right: int):
        # 将数据快排后返回
        if left >= right:  # 递归出口
            return 
        else:
            p = a[left]   # 取最左测为基准值
            i = left      # 设置两个游标
            j = right
            while(i != j):   # 直到相遇
                while(a[j] >= p and i < j):  # i < j 保证不会过头 要是过头的话后面都是比基准值大的数 循环不会停止了
                    j= j - 1;
                while(a[i] <= p and i < j):
                    i= i + 1;
                temp = a[i]                 # 在相遇之前,遇到右侧小的和左侧大的进行数值的交换
                a[i] = a[j]
                a[j] = temp
            a[left] = a[i]                  # 两个游标相遇,相遇的位置就是基准值应该在的位置,进行交换
            a[i] = p
            self.kp(a, left, i-1)           # 从基准值处分成两段,递归进行排序
            self.kp(a, i+1, right)

扩展: 当K很小的时候,可使用冒泡排序,因为冒泡排序的思想每一次就是确定好一个位置。这时相对的时间复杂度会小,为O(n * k)。
冒泡排序的思想: 冒泡排序属于一种典型的交换排序。
  交换排序顾名思义就是通过元素的两两比较,判断是否符合要求,如过不符合就交换位置来达到排序的目的。冒泡排序名字的由来就是因为在交换过程中,类似水冒泡,小(大)的元素经过不断的交换由水底慢慢的浮到水的顶端。
  冒泡排序的思想就是利用的比较交换,利用循环将第 i 小或者大的元素归位,归位操作利用的是对 n 个元素中相邻的两个进行比较,如果顺序正确就不交换,如果顺序错误就进行位置的交换。通过重复的循环访问数组,直到没有可以交换的元素,那么整个排序就已经完成。

所以,只需要进行K此冒泡,就把最大的交换到它应该在的位置。

class Solution:
    def findKth(self , a: List[int], n: int, K: int) -> int:
        for i in range(K):     # 注意这两个循环设置的范围
            for j in range(n-1):    
                if a[j] > a[j+1]:
                    temp = a[j+1]
                    a[j+1] = a[j]
                    a[j] = temp
        return a[n - K]

补充一个进阶的思路过程,如果感兴趣可以都实现一下:
https://mp.weixin.qq.com/s/FFsvWXiaZK96PtUg-mmtEw
链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值