215. Kth Largest Element in an Array

题目描述:

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

解决方法:

https://blog.csdn.net/qq_26286193/article/details/80683004

(c++):

runtime : 128ms:

class Solution {
public:
    int findKthLargest(vector& nums, int k) {
        return findKMax(nums,0,nums.size()-1,k);
    }
    int Partation(vector & nums, int low, int high){
        int pivotkey  = nums.at(low);
        while(low < high ){
            while(low < high && nums.at(high) >= pivotkey)
                high--;
            nums.at(low) = nums.at(high);
            while(low< high && nums.at(low)<= pivotkey)
                low++;
            nums.at(high) = nums.at(low);
        }
        nums.at(low) = pivotkey;
        return low;
    }
    int findKMax(vectornums,int low,int high,int k) {
        int mid = Partation(nums, low, high);
        //包括a[mid]的右半边长度
        int length_of_right = high - mid + 1;
        if (length_of_right == k) return nums.at(mid);
        else if (length_of_right > k) {
            //右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
            return findKMax(nums, mid + 1, high, k);
        }
        else {
            return findKMax(nums, low, mid - 1, k - length_of_right);
        }
    }
};

runtime : 108ms(改进中枢选取为三数取中):
选取左,中,右三个数中居中的那个数作为中枢

class Solution {
public:
    int findKthLargest(vector& nums, int k) {
        return findKMax(nums,0,nums.size()-1,k);
    }
    void swap(vector & nums , int one ,int two){
        int tmp = nums[one];
        nums[one]= nums[two];
        nums[two] = tmp;
    }
    int Partation(vector & nums, int low, int high){
        int mid = (high - low)/2 + low;
        if( nums[high] < nums[low]){
            swap(nums,low,high);
        }
        if(nums[mid] > nums[high]){
            swap(nums,low,high);
        }
        if(nums[mid] > nums[low]){
            swap(nums,low,high);
        }
        int pivotkey = nums[low];
        while(low < high ){
            while(low < high && nums.at(high) >= pivotkey)
                high--;
            nums.at(low) = nums.at(high);
            while(low< high && nums.at(low)<= pivotkey)
                low++;
            nums.at(high) = nums.at(low);
        }
        nums.at(low) = pivotkey;
        return low;
    }
    int findKMax(vectornums,int low,int high,int k) {
        int mid = Partation(nums, low, high);
        //包括a[mid]的右半边长度
        int length_of_right = high - mid + 1;
        if (length_of_right == k) return nums.at(mid);
        else if (length_of_right > k) {
            //右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
            return findKMax(nums, mid + 1, high, k);
        }
        else {
            return findKMax(nums, low, mid - 1, k - length_of_right);
        }
    }
};

runtime: 12ms(改进中枢为随机选取):

class Solution {
public:
    int findKthLargest(vector& nums, int k) {
        return findKMax(nums,0,nums.size()-1,k);
    }
    int Partation(vector & nums, int low, int high){
        srand((unsigned)time(NULL));
        int idx = (rand() % (high - low + 1)) + low;
        int pivotkey = nums[low];
        nums[low] = nums[idx];
        nums[idx] = pivotkey;
        pivotkey = nums[low];

        while(low < high ){
            while(low < high && nums.at(high) >= pivotkey)
                high--;
            nums.at(low) = nums.at(high);
            while(low< high && nums.at(low)<= pivotkey)
                low++;
            nums.at(high) = nums.at(low);
        }
        nums.at(low) = pivotkey;
        return low;
    }
    int findKMax(vectornums,int low,int high,int k) {
        int mid = Partation(nums, low, high);
        //包括a[mid]的右半边长度
        int length_of_right = high - mid + 1;
        if (length_of_right == k) return nums.at(mid);
        else if (length_of_right > k) {
            //右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
            return findKMax(nums, mid + 1, high, k);
        }
        else {
            return findKMax(nums, low, mid - 1, k - length_of_right);
        }
    }
};

runtime : 12ms:

class Solution {
public:
    int findKthLargest(vector& nums, int k) {
        return findKMax(nums,0,nums.size()-1,k);
    }
    int divide(vector & a, int low,int high) {
        //随机选一个元素作为枢纽元素
        //左边都是比枢纽元素小的,右边都是比枢纽元素大的
        srand((unsigned)time(NULL));
        int idx = (rand() % (high - low + 1)) + low;
        int tmp = a[low];
        a[low] = a[idx];
        a[idx] = tmp;
        tmp = a[low];
        while (low < high) {
            while (low= tmp) high--;
            if (low < high) {
                a[low] = a[high];
                low++;
            }
            while (low < high && a[low] <= tmp) low++;
            if (low < high) {
                a[high] = a[low];
                high--;
            }
        }
        //此时low=high,且low就是枢纽元应该在的位置编号,返回low
        a[low] = tmp;
        return low;
    }

    int findKMax(vectornums,int low,int high,int k) {
        int mid = divide(nums, low, high);
        //包括a[mid]的右半边长度
        int length_of_right = high - mid + 1;
        if (length_of_right == k) return nums.at(mid);
        else if (length_of_right > k) {
            //右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
            return findKMax(nums, mid + 1, high, k);
        }
        else {
            return findKMax(nums, low, mid - 1, k - length_of_right);
        }
    }
};

心得:

快速排序使用了分治法的策略。它的基本思想是,选择一个基准数(一般称之为枢纽元),通过一趟排序将要排序的数据分割成独立的两部分:在枢纽元左边的所有元素都不比它大,右边所有元素都比它大,此时枢纽元就处在它应该在的正确位置上了。
在本问题中,假设有N个数存储在数组a中。我们从a中随机找出一个元素作为枢纽元,把数组分为两部分。其中左边元素都不比枢纽元大,右边元素都不比枢纽元小。此时枢纽元所在的位置记为mid。

如果右半边(包括a[mid])的长度恰好为k,说明a[mid]就是需要的第k大元素,直接返回a[mid]。
如果右半边(包括a[mid])的长度大于k,说明要寻找的第k大元素就在右半边,往右半边寻找。
如果右半边(包括a[mid])的长度小于k,说明要寻找的第k大元素就在左半边,往左半边寻找。

中枢的选取对于算法的效率影响很大,所以一般情况下的,取第一个元素都是不可取的,需要优化,随机选取,或者3数取中。

你可能感兴趣的:(215. Kth Largest Element in an Array)