1、题目描述:
2、题解:
哈希表:力扣347. 前 K 个高频元素
方法1:暴力解法:
也就是我们进行排序(默认从小到大),然后倒序取第K个元素即可。
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
nums.sort()
return nums[-k]
方法2:分治思想,也即是快速排序中的主要部分进行变体,我们找到第len(nums)-k个元素即可。
方法1是很容易想到的,但是用这个方法会消耗掉额外的时间,如果能求出第K个最大元素,而不管后面的元素就好了,这样能节约时间。
import random
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
size = len(nums)
target = size - k
left = 0
right = size - 1
while True:
index = self.__partition(nums, left, right)
if index == target:
return nums[index]
elif index < target:
# 下一轮在 [index + 1, right] 里找
left = index + 1
else:
right = index - 1
# 循环不变量:[left + 1, j] < pivot
# (j, i) >= pivot
def __partition(self, nums, left, right):
random_index = random.randint(left,right)
nums[left],nums[random_index] = nums[random_index],nums[left]
pivot = nums[left]
j = left
for i in range(left + 1, right + 1):
if nums[i] < pivot:
j += 1
nums[i], nums[j] = nums[j], nums[i]
nums[left], nums[j] = nums[j], nums[left]
return j
当然我们可以对patition部分进行改进,我们用双指针进行partition
import random
class Solution:
# def findKthLargest(self, nums: List[int], k: int) -> int:
def findKthLargest(self, nums, k) :
size = len(nums)
target = size - k
left,right = 0,size - 1
while True:
index = self.partition(nums,left,right)
if index == target:
return nums[index]
elif index < target:
#下一轮在[index + 1,right]里找
left = index + 1
else:
right = index - 1
#[left + 1,j] < pivot ,(j,i) >= pivot
def partition(self,nums,left,right):
#双指针法
#随机切分元素,randint是包括左右区间的,也就是闭区间
random_index = random.randint(left,right)
nums[left],nums[random_index] = nums[random_index],nums[left] #交换第一个元素的位置和随机的位置
pivot = nums[left]
le = left + 1
ri = right
while True:
while le <= ri and nums[le] < pivot:
le += 1
while le <= ri and nums[ri] > pivot:
ri -= 1
if le > ri:
break
nums[le],nums[ri] = nums[ri],nums[le]
le += 1
ri -= 1
nums[left],nums[ri] = nums[ri],nums[left]
return ri
方法3:优先队列
优先队列的思路是很朴素的。因为第 K 大元素,其实就是整个数组排序以后后半部分最小的那个元素。因此,我们可以维护一个有 K 个元素的最小堆:
1、如果当前堆不满,直接添加;
2、堆满的时候,如果新读到的数小于等于堆顶,肯定不是我们要找的元素,只有新都到的数大于堆顶的时候,才将堆顶拿出,然后放入新读到的数,进而让堆自己去调整内部结构。
import heapq
class Solution:
# 使用容量为 k 的小顶堆
# 元素个数小于 k 的时候,放进去就是了
# 元素个数大于 k 的时候,小于等于堆顶元素,就扔掉,大于堆顶元素,就替换
def findKthLargest(self, nums: List[int], k: int) -> int:
size = len(nums)
if k > size:
raise Exception('程序出错')
L = []
for index in range(k):
# heapq 默认就是小顶堆
heapq.heappush(L, nums[index])
for index in range(k, size):
top = L[0]
if nums[index] > top:
# 看一看堆顶的元素,只要比堆顶元素大,就替换堆顶元素
heapq.heapreplace(L, nums[index])
# 最后堆顶中的元素就是堆中最小的,整个数组中的第 k 大元素
return L[0]
扩展知识:
快速排序:
思想:数组划分,找到一个元素,然后让大于它的元素在右边,小于它的在左边;然后再在左右区间继续划分。
import random
def quick_sort(x,l=0,r = None ):
n = len(x)
if n == 1:
return x
if r == None:
r = n - 1
if l < r:
index = partition(x,l,r)
quick_sort(x,l,index - 1)
quick_sort(x,index + 1,r)
def partition(nums,l,r):
#双指针
random_index = random.randint(l,r)
# nums[l],nums[random_index] = nums[random_index],nums[l]
pivot = nums[l]
left,right = l + 1,r
while True:
while left <= r and nums[left] < pivot:
left += 1
while l+1 <= right and nums[right] > pivot:
right -= 1
if left > right:
break
nums[left],nums[right] = nums[right],nums[left]
left += 1
right -= 1
nums[l],nums[right] = nums[right],nums[l]
return right
if __name__ == '__main__':
x = [7,8,5,2]
quick_sort(x)
print(x)
3、复杂度分析:
方法1:
时间复杂度:O(NlogN)
空间复杂度:O(1)
方法2:
时间复杂度:O(N)
空间复杂度:O(1)
方法3:
时间复杂度:O(Nlogk)
空间复杂度:O(k)