別再問我topk問題了

別再問我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 # 堆頂元素的最終位置
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章