题目
在未排序的数组中找到第 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 ≤ 数组的长度。
方案一(堆)
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = nums[:k]
heapq.heapify(heap)
for i in range(k, len(nums)):
if nums[i] > heap[0]: # 比堆中最小元素大
heapq.heapreplace(heap, nums[i])
return heap[0]
或
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
return heapq.nlargest(k, nums)[-1]
方案二(分治)
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
# 快排思想+问题转化:第 k 个最大元素也就是第 N - k 个最小元素
def partition(left, right, pivot_index):
pivot = nums[pivot_index]
# 将 pivot 移到最后
nums[right], nums[pivot_index] = nums[pivot_index], nums[right]
# 将小于 pivot 的移动在前面
store_index = left
for i in range(left, right):
if nums[i] < pivot:
nums[i], nums[store_index] = nums[store_index], nums[i]
store_index += 1
# 最后一个节点为分界点
nums[right], nums[store_index] = nums[store_index], nums[right]
# 返回分区点
return store_index
def select(left, right, k_smallest):
if left == right:
return nums[left]
pivot_index = random.randint(left, right)
pivot_index = partition(left, right, pivot_index)
if k_smallest == pivot_index:
return nums[pivot_index]
elif k_smallest < pivot_index:
return select(left, pivot_index - 1, k_smallest)
else:
return select(pivot_index + 1, right, k_smallest)
return select(0, len(nums) - 1, len(nums) - k)