快速选择

题目

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

题解

方法一:暴力解法

思路:进行完整的排序,再从右至左输出第n-k个元素

进行快速排序后
- 时间复杂度:O(nlogn)
- 空间复杂度:O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def findKthLargest(self, nums, k) -> int:
self.quick_sort(nums,0,len(nums))
return nums[len(nums)-k]
def quick_sort(self,nums,lo,hi):
if lo+1>=hi:
return
first =lo
last =hi-1
pivot=nums[first]
while first<last:
while first<last and nums[last]>=pivot:
last = last-1
nums[first]=nums[last]
while first<last and nums[first]<=pivot:
first=first+1
nums[last] = nums[first]
nums[first]=pivot
self.quick_sort(nums,lo,first)
self.quick_sort(nums,first+1,hi)
1
2
3
4
a = Solution()
nums=[3,2,3,1,2,4,5,5,6]
k = 2
a.findKthLargest(nums,k)
5

方法二:快速选择

思路:利用快速排序,每次都能将一个元素放在其既定位置,即每趟:nums[lo:p-1]<nums[p]<nums[p+1:hi],如此每趟能得出一个p,若p<target=len(nums)-k则说明第k个大的元素在(p和hi之间),反之在(lo和p之间)

考虑快排对已经有序的排序复杂度高问题,每次选pivot时,随机选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import random
class Solution:
def findKthLargest(self, nums, k) -> int:
target = len(nums)-k
lo = 0
hi = len(nums)-1
while lo<=hi:
p = self.partion(nums,lo,hi)
if p<target:
lo=p+1
elif p>target:
hi =p-1
else:
return nums[p]

def partion(self,nums,lo,hi):
if lo<hi: # 随机选取pivot
rindex= random.randint(lo,hi)
nums[lo],nums[rindex]=nums[rindex],nums[lo]
pivot = nums[lo]
while lo<hi:
while lo<hi and nums[hi]>=pivot:
hi=hi-1
nums[lo]=nums[hi]
while lo<hi and nums[lo]<=pivot:
lo = lo+1
nums[hi]=nums[lo]
nums[lo]=pivot
return lo
1
2
3
4
a = Solution()
nums=[3,2,3,1,2,4,5,5,6]
k = 2
a.findKthLargest(nums,k)
5

算法导论中提到的快速排序,一趟就分完

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import random
class Solution:
def findKthLargest(self, nums, k) -> int:
target = len(nums)-k
lo = 0
hi = len(nums)-1
while lo<=hi:
p = self.partion(nums,lo,hi)
if p<target:
lo=p+1
elif p>target:
hi =p-1
else:
return nums[p]

def partion(self,nums,lo,hi):
random_index = random.randint(lo,hi)
nums[random_index],nums[lo]=nums[lo],nums[random_index]
pivot = nums[lo]
j=lo
for i in range(lo+1,hi+1):
if nums[i]<pivot:
j+= 1
nums[i],nums[j]=nums[j],nums[i]
nums[lo],nums[j]=nums[j],nums[lo]
return j
1
2
3
4
a = Solution()
nums=[3,2,3,1,2,4,5,5,5,6,6]
k = 2
a.findKthLargest(nums,k)
6