python leetcode 215. 数组中的第K个最大元素

在未排序的数组中找到第 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 ≤ 数组的长度。

 这一题可能是高频考题吧!涉及到快速排序和堆排序。

针对本题,第一想法:先从大到小排序,然后取第K个值。我掌握最熟练的冒泡排序,但是它的时间复杂度太高了,为O(n^2),运行完了提示时间超出了限制。

解法一:快速排序

思想:分而治之。设立一个基准值pivot,通过一趟排序后,大于pivot的放在右边,小于pivot的数放在左边。对左右两边分别递归排序,直至整个数组排好序。时间复杂度O(nlogn),空间复杂度O(logn)(递归使用栈的空间代价)

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def quicksort(arr,l,r):
            if l>=r:
                return arr
            pivot = arr[l]
            low = l
            high = r
            while(l<r):
                while(l<r and arr[r]>=pivot):
                    r = r-1
                arr[l] = arr[r]
                while(l<r and arr[l]<=pivot):
                    l = l+1
                arr[r] = arr[l]
            arr[l] = pivot
            quicksort(arr,low,l-1)
            quicksort(arr,l+1,high)
        quicksort(nums,0,len(nums)-1)
        return nums[len(nums)-k]

 

 解法二:快速选择排序

在快速排序的基础上,可以进一步改进为快速选择排序。即判断较大值排序好的序列长度是否为K,如果为K,直接返回;如果小于K,则继续对左子序进行排序;如果大于K,则对右子序进行排序即可。

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        low,high = 0,len(nums)-1
        def quicksort(arr,l,r):
            if l>=r:
                return l
            pivot = arr[l]
            low = l
            high = r
            while(l<r):
                while(l<r and arr[r]>=pivot):
                    r = r-1
                arr[l] = arr[r]
                while(l<r and arr[l]<=pivot):
                    l = l+1
                arr[r] = arr[l]
            arr[l] = pivot
            return l
        

        while True:
            l = quicksort(nums,low,high)
            if len(nums)-l == k:
                return nums[l]
            elif len(nums)-l<k:
                high = l-1
            else:
                low = l+1

解法三:堆排序

对于一个堆(Heap)来说,1.完全二叉树2.所有父节点都大于(或小于)子节点。一定要从上到下,从左到右依次添加。

分为大顶堆(升序排列)(父节点大于两个子节点)和小顶堆 (降序排列)。平均时间复杂度O(nlogn)。空间复杂度是O(logn)。

对于一个完全二叉树,节点标号为i,那么父节点标号为(i-1)/2,向下取整;左子节点标号为2i+1,右子节点为2i+2

从最后一个节点的父节点开始heapify,首先将整个二叉树进行堆化,然后交换根节点和最后一个节点,取出最后一个节点,对新的二叉树进行堆化。

有个博主视频讲解堆排序很清晰:https://www.bilibili.com/video/BV1Eb41147dK/?spm_id_from=333.788.recommend_more_video.-1

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def swap(arr,i,j):
            temp = arr[i]
            arr[i] = arr[j]
            arr[j] = temp

        def heapify(arr,n,i):
            c1 = 2*i+1
            c2 = 2*i+2
            max = i
            if c1<n and arr[c1]>arr[max]:
                max = c1
            if c2<n and arr[c2]>arr[max]:
                max = c2
            if i!=max:
                swap(arr,i,max)
                heapify(arr,n,max)

        def build_heap(arr,n):
            last_node = n-1
            parent = int((last_node-1)/2)
            for i in range(parent,-1,-1):
                heapify(arr,n,i)
        
        def heap_sort(arr,n):
            build_heap(arr,n)
            for i in range(n-1,-1,-1):
                swap(arr,i,0)
                heapify(arr,i,0)
        
        heap_sort(nums,len(nums))
        return nums[len(nums)-k]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值