數組中第K大(小)的元素

題目描述:在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序後的第 k 個最大的元素,而不是第 k 個不同的元素。

這是一道排序問題?顯然當數組元素N很大時,採用一般O(N^2)的排序算法(如冒泡排序)一定會超時。

所以這裏可以使用快排和堆排。這裏快排和堆排的思想就不詳細介紹了,有興趣的可以去看我的其他文章或者直接baidu一下。

1.直接快速排序,對整個數組進行排序(156ms)

lass Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        quick_sort(nums, 0, nums.size() - 1);
        return nums[nums.size() - k];
    }
    void quick_sort(vector<int>& nums, int l, int r){

        if(l < r){
            int pivot = partition(nums, l, r);
            quick_sort(nums, l, pivot - 1);
            quick_sort(nums, pivot + 1, r);
        }
    }

    int partition(vector<int>& nums, int l, int r){
        int p = nums[l];//i的位置已經記錄下來
        int i = l, j = r;
        while(i < j){
            //先將大的往後移動
            while(i < j && nums[j] >= p){
                j --;
            }
            nums[i] = nums[j];//右邊第一個比p小的數
            while(i < j && nums[i] <= p){
                i ++;
            }
            nums[j] = nums[i];//左邊第一個比p大的數
        }
        nums[i] = p;
        return i;
    }
};

2.題目要求是找到第K個大的數即可,所以在quick_sort()函數中,每次partition返回的pivot的索引值和K進行比較,就可以每次減少一部分的排序:(52ms)

 int quick_sort(vector<int>& nums, int l, int r, int k){

        if(l == r) return nums[l];
        int pivot = partition(nums, l, r);
        if(pivot == nums.size() - k){
            return nums[pivot];
        }
        else if(pivot > nums.size() - k){//比目標值大,在左邊
            return quick_sort(nums, l, pivot - 1, k);
        }
        else{ 
            return quick_sort(nums, pivot + 1, r, k);
        }
    }

3.在快排中,選擇pivot對於整體速度影響很大,所以這裏可以採用隨機選擇index的方法。在partition()中加入以下代碼:(16ms)

srand(time(NULL));//隨機種子
int r_pos = rand() % (r - l + 1) + l;

swap(nums[l], nums[r_pos]);

4.堆排序

建(大頂)堆-調整-堆排序(“取出前k個大的數即可”)

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        
        return buildHeap(nums, k);
    }

    int buildHeap(vector<int>& nums, int k){
        //建成一個大頂堆
        int n = nums.size();
        for(int i = n / 2; i >= 0; -- i){
            downAdjust(nums, i, n);
        }
        
        for(int j = 0; j < k; j ++){
            swap(nums[0], nums[n - 1 - j]);
            downAdjust(nums, 0, n - 1 - j);
            //堆排序,將最大的,第二大的...,第k大的依次“取出”
        }
        return nums[n - k];
    }

    void downAdjust(vector<int>& nums, int i, int n){
        //left & right child-node 2*i + 1 / 2*i + 2
        int l = 2 * i + 1;
        int r = 2 * i + 2;
        int maxidx = i;

        if(l < n && nums[l] > nums[maxidx]){   
            maxidx = l;
        }
        if(r < n && nums[r] > nums[maxidx]){
            maxidx = r;
        }
        if(maxidx != i){
            swap(nums[i], nums[maxidx]);//maxidx位置和原i位置交換
            downAdjust(nums, maxidx, n);
        }
    }
 
};

以上就是這篇的主要內容,如有問題或疑惑,請您指出。謝謝!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章