zoukankan      html  css  js  c++  java
  • [LeetCode] Kth Largest Element in an Array

    https://leetcode.com/problems/kth-largest-element-in-an-array/

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

    For example,
    Given [3,2,1,5,6,4] and k = 2, return 5.

    Note:
    You may assume k is always valid, 1 ≤ k ≤ array's length.

    方法1 排序

    最容易想到的方法是使用排序来做,按从大到小进行排序,然后返回k-1位置处的元素,但是o(nLogn)的时间复杂度显然不是我们想要的。

    方法2 使用大顶堆,进行Heap Select

    首先对数组元素进行heapify,建立一个大顶堆,既然是要找第k大的元素,那么可以对该大顶堆进行k-1次extractMax()操作,此时堆顶即为第K大的元素。建堆的时间复杂度为o(n),同时每一次extractMax()操作都需要进行时间复杂度为o(logn)的heapify()操作来维持堆序性,因此总的时间复杂度为o(n + klogn),显然优于排序。代码如下:

    /**
     * Author : Jianxin Zhou
     */
    
    class Solution {
    public:
        int findKthLargest(vector<int>& nums, int k) {
            heapSize_ = nums.size();
            
            createMaxHeap(nums);
            for (int i = 0; i < k - 1; ++i) {
                exactMax(nums);
            }
            
            return nums[0];
        }
        
    private:
        int heapSize_;
        
        inline int leftChild(int parent) {
            return (parent << 1) + 1;
        }
        
        inline int rightChild(int parent) {
            return (parent << 1) + 2;
        }
        
        inline int parent(int child) {
            return (child - 1) >> 1;
        }
        
        void createMaxHeap(vector<int> &nums) {
            int indexForHeapify = parent(heapSize_ - 1);
            for (int i = indexForHeapify; i >= 0; --i) {
                maxHeapify(nums, i);
            }
        }
        
        // 从位置i处进行下滤,保持大顶堆的偏序性
        void maxHeapify(vector<int> &nums, int i) {
            int left = leftChild(i);
            int right = rightChild(i);
            int largest = i;
            
            if (left < heapSize_ && nums[left] > nums[largest]) {
                largest = left;
            }
            
            if (right < heapSize_ && nums[right] > nums[largest]) {
                largest = right;
            }
            
            if (largest != i) {
                swap(nums[largest], nums[i]);
                maxHeapify(nums, largest);
            }
        }
        
        void exactMax(vector<int> &nums) {
            swap(nums[0], nums[heapSize_ - 1]);
            --heapSize_;
            maxHeapify(nums, 0);
        }
    };

    方法3 使用QuickSelect

    快速排序的核心思想在于,挑选一个pivot元素,并将其放在经排序后应该所处的正确的位置,然后再递归的对该pivot两边的元素进行partition操作,挑选pivot元素置于正确的位置。(简单分析下最坏情况下的时间复杂度,每次挑选的pivot位置最终所处的正确的位置都在数组的两端,那么每次对该pivot元素进行归位时,需要o(n)的时间复杂度,那么最坏情况是o(n2))。

    那么对于解决本问题而言,我们不必进行完整的快排操作,只要当前pivot元素最终落在第k大的元素的位置时,我们即停止快排。平均时间复杂度为o(n),代码如下:

    class Solution {
    public:
        int findKthLargest(vector<int> &nums, int k) {
            return quickSelect(nums, 0, nums.size() - 1, k);
        }
        
    private:
        int quickSelect(vector<int> &nums, int left, int right, int k) {
            int pivot = right;
            int i = left - 1;
            
            // 遍历数组,将当前数组中数值大于pivot位置的元素均移至数组开始
            // 那么当遍历结束时,++i位置的元素即为pivot元素应该在的位置
            for (int j = left; j < right; j++) {
                if (nums[j] > nums[pivot]) {
                    swap(nums[++i], nums[j]);
                }
            }
            swap(nums[pivot], nums[++i]);
            
            // 递归基
            if (i - left + 1 == k) {
                return nums[i];
            }
            
            if (i - left + 1 > k) {
                return quickSelect(nums, left, i - 1, k);
            } else if (i - left + 1 < k) {
                return quickSelect(nums, i + 1, right, k - (i - left + 1));
            } 
        }
    };
  • 相关阅读:
    c++作业2 9.22
    c++作业1 9.22
    c++练习题2
    c++练习题1
    10.10作业3
    10.10作业2
    10.10作业 1
    9.22作业5
    9.22作业4
    9.22zuo
  • 原文地址:https://www.cnblogs.com/jianxinzhou/p/4676122.html
Copyright © 2011-2022 走看看