题目
在未排序的数组中找到第 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)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
题意理解
先将数组降序,再找出符合题意的第 k 个最大元素。
sort函数
直接利用sort()函数对数组进行降序排序。
JDK默认是快速排序
快速排序原理
将一组无序数据a[1]、a[2]、……a[n]按升序排列:
- 首先任取数据a[x]作为基准;
- 比较a[x]与其它数据并排序,使a[x]排在数据的第k位,并且使a[1] ~ a[k-1]中的每一个数据 < a[x],a[k+1] ~ a[n]中的每一个数据 > a[x];
- 然后采用分治的策略分别对a[1] ~ a[k-1] 和 a[k+1] ~ a[n]两组数据进行快速排序。
冒泡排序
目前最熟悉最先想到的排序方法,两层循环遍历,通过比较相邻元素交换大小值位置。
- 时间复杂度 O(N2)
N 表示数组长度,最坏情况是原数组升序排列。
堆排序
堆积是一个近似完全二叉树的结构,并满足性质:子结点的键值或索引总是小于(或者大于)它的父节点。
算法描述
- 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
- 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
- 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。
不断重复此过程直到有序区的元素个数为 n-1,则整个排序过程完成。
解题思路
- 取nums前K个元素建立大小为K的最小堆;
- 剩余k+1到N个元素依次和堆顶比较,比堆顶大则替换当前堆顶,并维护最小堆;
- 最终最小堆里是前K大的元素,堆顶为前K大的元素中最小的元素,即Kth大的元素
提交代码
sort函数
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
nums.sort()
return nums[-k]
冒泡排序
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
n = len(nums)
for i in range(n-1):
for j in range(n-1-i):
if nums[j] < nums[j+1]:
temp = nums[j]
nums[j] = nums[j+1]
nums[j+1] = temp
return nums[k-1]
超出时间限制
输入数组元素数量很多时耗时长。
堆排序
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
# 替换nums[i]后维护最小堆:自顶向下调整新元素位置,直至该值满足(parent value < son value)
def shift(i,k):
flag=0
while (i*2+1)<k and flag==0 :
t=i
if nums[i]>nums[2*i+1]:
t=2*i+1
if (i*2+2)<k and nums[t]>nums[2*i+2] :
t=2*i+2
if t==i:
flag=1
else :
nums[i],nums[t]=nums[t],nums[i]
i=t
#O(k):建立大小为K的最小堆, k/2-1是最后一个非叶节点,因为shift是向下调整,所以倒序从最下面出发,不然(4 32 1)->(2 34 1)->(2 14 3)->(2 14 3) 结果不对
for i in range(k/2,-1,-1):
shift(i,k)
#O((N-k)logK),剩余元素依次比较替换
for i in range(k,len(nums)):
if nums[0]<nums[i]:
nums[0]=nums[i]
shift(0,k)
return nums[0]
#https://leetcode-cn.com/problems/kth-largest-element-in-an-array/solution/quan-shou-xie-20xing-kge-yuan-su-de-zui-xiao-dui-d/
总结
学习新的排序思想——堆排序,适合解决 top k 的问题。