题目:
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
思路:
方法1,先快速排序,再从前往后索引到第长度减k个最小元素,即第k个最大的元素。但是这种方法时间和空间复杂度太高,需要把全部元素都排序一遍,再索引。具体过程是先执行快排函数,第一步是让数组的第一个元素当基准,将它放在合适的位置,同时将数组分为基准左右两个部分,这两个部分在分别调用快排函数,直到左右指针相同,跳出循环,排序完成。
划分为两部分的函数具体过程:
将左指针的元素作为基准,然后认为将基准元素提取出来,开始遍历数组,左边指针空,遍历右边,如果右指针对应的数大于或者基准,不用移动,将右指针左移一位,如果右指针的元素小于基准,就将它的值给到左指针空的位置,左指针向右移动一位,现在右指针为空,这样依次遍历,让大于基准的数往右放,小于基准的数往左放,直到两个指针相同了,跳出循环,将基准这个数放到左指针的位置上,现在左指针的位置就是分成两段的中间位置,然后左右两部分再递归调用排序函数。
最后索引到数组中第k个最大的元素返回即可。
方法2,基于快速排序的选择方法
这个过程是递归调用快速选择函数,同样的用函数将数组分成两部分,这个过程优化了快排的步骤,这里在数组区间内随机选择一个数作为基准,然后将小于基准的数都放到基准前面,大于基准的数都放到基准后面,再将基准数放到中间的位置,这个位置就是它的正确位置,然后读取这个基准的索引,看它在我们要找的索引前面还是后面,如果在前面,那就将递归调用的区间设为后面,如果在后面,就将递归调用的区间设为前面,减少递归次数,如果这个索引正是我们要找到元素,直接返回结果即可。
这样随机化的时间复杂度是O(n),空间复杂度和递归调用的次数有关。
class Solution(object):
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
# 原始快排,太慢了
# def quicksort(nums,left,right):
# if left < right:
# pivotpos = partion(nums,left,right)
# quicksort(nums,left,pivotpos-1)
# quicksort(nums,pivotpos+1,right)
# return nums
# def partion(nums,left,right):# 左边索引作为基准,可以这样操作
# pivot = nums[left]
# while left < right:
# while left < right and nums[right] >= pivot:
# right -= 1
# nums[left] = nums[right]
# while left < right and nums[left] <= pivot:
# left += 1
# nums[right] = nums[left]
# nums[left] = pivot
# return left
# length = len(nums)
# left = 0
# right = length - 1
# quicksort(nums,left,right)
# return nums[length-k]
# 基于快速排序的选择方法
def quickselect(start,end,nums,k):
if start == end:
return nums[start]
mid = partion(start,end,nums)
if mid == len(nums)-k:
return nums[mid]
elif mid < len(nums)-k:
return quickselect(mid+1,end,nums,k)
elif mid > len(nums)-k:
return quickselect(start,mid-1,nums,k)
def partion(start,end,nums):# 随机选取,但要全部遍历到,所以这个区间范围内要全部移动好
p = random.randrange(start,end+1)# 随机选取的话,快排过程和前面不同
pivot = nums[p]
nums[end],nums[p] = nums[p],nums[end]
mid = start
for i in range(start,end):
if nums[i] <= pivot:
nums[i],nums[mid] = nums[mid],nums[i]
mid += 1
nums[mid],nums[end] = nums[end],nums[mid]
return mid
res = quickselect(0,len(nums)-1,nums,k)
return res