📌  相关文章
📜  未排序数组中的第 K 个最小或最大元素 |设置 4(1)

📅  最后修改于: 2023-12-03 15:26:32.104000             🧑  作者: Mango

未排序数组中的第 K 个最小或最大元素

在一个未排序的数组中,找到第 k 个最小或最大元素。可以假设 k 总是有效的,即 1 ≤ k ≤ 数组长度。

方法一:排序

最简单直观的方法是先排序,然后直接返回第 k 个元素。时间复杂度为 $O(n \log{n})$。

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        nums.sort()
        return nums[-k]
class Solution:
    def findKthSmallest(self, nums: List[int], k: int) -> int:
        nums.sort()
        return nums[k-1]
方法二:快速选择(Quick Select)

由于我们不需要对整个数组进行排序,因此可以考虑使用快速排序的思想,选择一个 pivot,将数组划分为小于 pivot 和大于 pivot 的两部分,然后再递归的处理其中一部分。具体算法如下:

  1. 选择一个 pivot,将数组划分为小于 pivot 和大于 pivot 的两部分;
  2. 如果第 k 小的元素位于小于 pivot 的部分,那么我们只需要递归处理小于 pivot 的部分;
  3. 如果第 k 小的元素位于大于 pivot 的部分,那么我们只需要递归处理大于 pivot 的部分,并将 k 减去小于 pivot 的部分的长度;
  4. 否则,当前 pivot 即为第 k 小的元素,直接返回 pivot。

时间复杂度:平均情况下为 $O(n)$,最坏情况下时间复杂度退化为 $O(n^2)$,但可以通过随机化 pivot 来避免最坏情况的发生。

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def quickSelect(left, right, k):
            if left == right:
                return nums[left]
            
            pivot_idx = random.randint(left, right)
            pivot_idx = partition(left, right, pivot_idx)
            
            if k == pivot_idx:
                return nums[k]
            elif k < pivot_idx:
                return quickSelect(left, pivot_idx - 1, k)
            else:
                return quickSelect(pivot_idx + 1, right, k)
        
        def partition(left, right, pivot_idx):
            pivot_value = nums[pivot_idx]
            nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx]
            store_idx = left
            
            for i in range(left, right):
                if nums[i] < pivot_value:
                    nums[store_idx], nums[i] = nums[i], nums[store_idx]
                    store_idx += 1
            nums[right], nums[store_idx] = nums[store_idx], nums[right]
            
            return store_idx
        
        return quickSelect(0, len(nums) - 1, len(nums) - k)
class Solution:
    def findKthSmallest(self, nums: List[int], k: int) -> int:
        def quickSelect(left, right, k):
            if left == right:
                return nums[left]
            
            pivot_idx = random.randint(left, right)
            pivot_idx = partition(left, right, pivot_idx)
            
            if k == pivot_idx:
                return nums[k]
            elif k < pivot_idx:
                return quickSelect(left, pivot_idx - 1, k)
            else:
                return quickSelect(pivot_idx + 1, right, k)
        
        def partition(left, right, pivot_idx):
            pivot_value = nums[pivot_idx]
            nums[pivot_idx], nums[right] = nums[right], nums[pivot_idx]
            store_idx = left
            
            for i in range(left, right):
                if nums[i] < pivot_value:
                    nums[store_idx], nums[i] = nums[i], nums[store_idx]
                    store_idx += 1
            nums[right], nums[store_idx] = nums[store_idx], nums[right]
            
            return store_idx
        
        return quickSelect(0, len(nums) - 1, k - 1)