別再問我topk問題了
215. 數組中的第K個最大元素
在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序後的第 k 個最大的元素,而不是第 k 個不同的元素
- 全局排序法
快速排序,然後直接輸出第k個最大的元素,時間複雜度O(nlogn)
- 冒泡法
如果k比較小,考慮用冒泡法
class Solution:
def findKthLargest(self, nums: List[int], m: int) -> int:
k = 0
if len(nums) == m:
return min(nums)
max_x = -99999999999999
while(k < m):
index_max = 0
for i in range(k, len(nums)):
if nums[i] >= max_x:
max_x = nums[i]
index_max = i
nums[k], nums[index_max] = nums[index_max], nums[k]
k += 1
max_x = -99999999999999
return nums[m-1]
- 來自快排分片+減治的算法
主要的算法思想是,快速排序每次都會將一個元素放到最終排序數組中正確的位置,保證比這個元素小的所有元素都放在該元素的左邊位置,比該元素大的元素都會放在該元素右邊的位置。如果我們恰好找到這個位置就是第k個最大元素的位置,那麼就可以直接返回。如果不是則到這個位置的左邊或者右邊繼續尋找。算法複雜度爲O(2n)
import random
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
low = 0
high = len(nums)-1
return self.RS(nums, low, high, len(nums)-k) #第k個最大的元素就是第len(nums)-k個最小的元素
def RS(self, nums, left, right, k):
if left == right:
return nums[left]
pivot_index = random.randint(left, right) # 隨機選擇一個元素,如果選用最右面的元素,在極端的情況下快速排序會退化到O(n2)
pivot_index = self.partion(nums, left, right, pivot_index)
if pivot_index == k:
return nums[pivot_index]
elif pivot_index > k:
return self.RS(nums, left, pivot_index-1, k) #在pivot的左邊繼續尋找
elif pivot_index < k:
return self.RS(nums, pivot_index+1, right, k)
def partion(self, nums, left, right, pivot_index):
pivot = nums[pivot_index]
nums[right], nums[pivot_index] = nums[pivot_index], nums[right]
store_index = left
for i in range(left, right):
if nums[i] < pivot: #小於nums[pivot]的都放在nums[pivot]的左邊
nums[store_index], nums[i] = nums[i], nums[store_index]
store_index += 1
nums[right], nums[store_index] = nums[store_index], nums[right] #將nums[pivot]放到正確的位置, 比nums[pivot]小的元素都在最左邊,比nums[pivot]大的元素都在最右邊
return store_index # 返回nums[pivot]的位置
- 建立一個k大小的小根堆。
這個小根堆中保存數組中最大的k個元素,其中第k大的元素放在堆頂。建堆是O(k)的複雜度,調整一次堆的時間複雜度是O(logk)
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
for i in range(k//2 -1, -1, -1):
self.Heap(nums, i, k) #建立一個k個大小的小根堆
for j in range(k, len(nums)):
if nums[j] > nums[0]: #如果當前元素比堆頂元素大,將其入堆,並且調整堆
nums[0], nums[j] = nums[j], nums[0]
self.Heap(nums, 0, k)
# print(nums)
return nums[0]
def Heap(self, nums, root, length):
temp = nums[root]
i = root * 2 + 1
while(i < length): # 尋找堆頂元素正確位置的循環
if i + 1 < length and nums[i+1] < nums[i]: # 左右子結點誰更小
i += 1
if temp > nums[i]: # 子結點比父節點更小,需要將子結點調整到父節點位置
nums[root] = nums[i]
else: #尋找完畢
break
root = i # 在該父節點上繼續調整
i = i * 2 + 1 #下一個子結點
nums[root] = temp # 堆頂元素的最終位置