leetcode-寻找数组第K个最大数

前言

吸烟有害健康,切记。最近要抓紧练车,考完驾照。今天大扫除,有点烦躁,不过寝室干净了,也是有点舒坦的。开始解题吧!回头加一句,一篇博客都写完了,还没回我。o(╥﹏╥)o

题目

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

思路

对于这个问题,可以说思路是比较清晰的,不过就是对这个数组进行排序而,然后输出对应下标的元素就行,不过我们还是要追求时间复杂度与空间复杂度尽可能的小。一开始我尝试着写了一个快排进行解决,不过不得不说,leetcode的测试用例也是蛮好,毕竟我们能想到的别人也能想到,快排的效率让我诧异,2016ms,只能说测试用例可能都是快排的最坏情况了。
快排执行结果

不过这样才有改进的空间嘛!这个时候我想到一个结构————堆.小顶堆完美契合这道题。首先将数组中前k个数构造一个节点数为k的小顶堆,然后剩余的数与根节点进行比较,再下沉调整,最后将根节点输出即可。代码如下:

代码

class Solution:


    def findKthLargest(self, nums: List[int], k: int) -> int:
        self.build_heap(nums,k)
        # print("小顶堆构造完毕")
        for i in range(k,len(nums)):
            if nums[i] > nums[0]:
                nums[0] = nums[i]
                self.maintain(nums,0,k)
        return nums[0]

    def maintain(self,List, index, length):
    # print("父节点位置:",index,"父节点:",List[index])
        temp = List[index]
        childindex = 2 * index + 1
        # print("左子节点 :",childindex)
        while childindex < length:
            if (childindex + 1 < length ) and (List[childindex + 1] < List[childindex]): #判断左右子节点的大小
                childindex = childindex + 1
                # print("右节点小")
            if temp <= List[childindex]:
                break
            # print("位置:",childindex,"子节点 ",List[childindex])
            List[index] = List[childindex]
            index = childindex
            childindex = 2*childindex+1
            # print('节点下沉',List)
        List[index] = temp

    def build_heap(self,list,length):
        i = int((length-2)/2) # 深度
        while i>=0 :
            self.maintain(list,i,length)
            i -= 1

堆的执行过程:

数组为: [7, 9, 4, 2, 5, 1, 3, 6, 8, -1]
构建小顶堆
第2层
父节点的数组下标: 2 父节点值: 4
左子节点的数组下标 : 5
子节点的数组下标: 5 子节点值:  1
节点下沉 [7, 9, 1, 2, 5, 1, 3, 6, 8, -1]
下沉结束: [7, 9, 1, 2, 5, 4, 3, 6, 8, -1]
第1层
父节点的数组下标: 1 父节点值: 9
左子节点的数组下标 : 3
子节点的数组下标: 3 子节点值:  2
节点下沉 [7, 2, 1, 2, 5, 4, 3, 6, 8, -1]
下沉结束: [7, 2, 1, 9, 5, 4, 3, 6, 8, -1]
第0层
父节点的数组下标: 0 父节点值: 7
左子节点的数组下标 : 1
右节点小
子节点的数组下标: 2 子节点值:  1
节点下沉 [1, 2, 1, 9, 5, 4, 3, 6, 8, -1]
子节点的数组下标: 5 子节点值:  4
节点下沉 [1, 2, 4, 9, 5, 4, 3, 6, 8, -1]
下沉结束: [1, 2, 4, 9, 5, 7, 3, 6, 8, -1]
小顶堆构造完毕

 比较其余数字
父节点的数组下标: 0 父节点值: 3
左子节点的数组下标 : 1
子节点的数组下标: 1 子节点值:  2
节点下沉 [2, 2, 4, 9, 5, 7, 3, 6, 8, -1]
右节点小
下沉结束: [2, 3, 4, 9, 5, 7, 3, 6, 8, -1]
父节点的数组下标: 0 父节点值: 6
左子节点的数组下标 : 1
子节点的数组下标: 1 子节点值:  3
节点下沉 [3, 3, 4, 9, 5, 7, 3, 6, 8, -1]
右节点小
子节点的数组下标: 4 子节点值:  5
节点下沉 [3, 5, 4, 9, 5, 7, 3, 6, 8, -1]
下沉结束: [3, 5, 4, 9, 6, 7, 3, 6, 8, -1]
父节点的数组下标: 0 父节点值: 8
左子节点的数组下标 : 1
右节点小
子节点的数组下标: 2 子节点值:  4
节点下沉 [4, 5, 4, 9, 6, 7, 3, 6, 8, -1]
子节点的数组下标: 5 子节点值:  7
节点下沉 [4, 5, 7, 9, 6, 7, 3, 6, 8, -1]
下沉结束: [4, 5, 7, 9, 6, 8, 3, 6, 8, -1]
第6大的数为:4

总结

在评论区看到一些人总结调用了python内置库的sort()函数,说实话我蛮不屑这些拿内置函数来刷题的人,不过试了一下,真香。比堆排序快一点,那sort()函数的机制并不是用来一个快排这么简单,以前觉得sort()=快排,现在看来sort()还是一个优化过的快排,内部对不同情况进行不同的排序使用与它们的组合。我还只是个井底之蛙。不过你终于回我了。加油!!!

赏瓶可乐吧(*^▽^*)