zoukankan      html  css  js  c++  java
  • Leetcode 215. 数组中的第K个最大元素

    题目

    在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

    示例 1:
    
    输入: [3,2,1,5,6,4] 和 k = 2
    输出: 5
    
    示例 2:
    
    输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
    输出: 4
    

    解法一:用快排partition思路

    class Solution {
    public:
        int findKthLargest(vector<int>& nums, int k) {
    		int l = 0, r = nums.size();
            srand(time(NULL));
    		while(l<r) {
    			int km = partition(nums, l, r);
    			if (km == k-1){
    				return nums[km];
    			}
    			else if (km < k-1) {
    				l = km+1;
    			}
    			else {
    				r = km;
    			}
    		} 
    		return -1;
        }
    private:
    	// [start, end) privot:nums[start]
    	int partition(vector<int>& nums, int start, int end) {
    		if(start == end-1)
    			return start;
            swap(nums[start], nums[rand()%(end-start)+start]);
    		int i = start, j = end - 1;
    		int pivot = nums[start];
    		while(i<j){
                while(i<j && nums[j] < pivot) --j;
    			while(i<j && nums[i] >= pivot) ++i;	
    			if(i<j) {
    				swap(nums[i], nums[j]);
    			} 
    		}
    		swap(nums[start],nums[j]);
    		return j;
    	}
    };
    

    主要思想:将区间[start, end)中第一个元素作为主元pivot,把该区间分为大于等于主元和小于主元2部分,返回主元所在的下标
    我们通过主元所在的位置,就能知道主元是第几大的元素
    主义第一个元素应该随机选取,否则最坏情况算法会退化成O(n^2).我们这里partition是左边元素大于主元,右边元素小于主元。所以最坏情况下是数组从小到大已排序好。

    拓展:快排的partition有3中写法

    #include<vector>
    #include<iostream>
    using namespace std;
    
    #if 0
    /* swap 写法 */
    int partition(vector<int>& nums, int lo, int hi) {
    	int pivot = nums[lo];
    	int i = lo, j = hi - 1;
    	while(i < j) {
    		while(pivot < nums[j] && i < j) --j;
    		while(pivot >= nums[i] && i < j) ++i;
    		if(i < j)
    			swap(nums[i], nums[j]);
    	}
    	swap(nums[lo], nums[j]);
    	return j;
    }
    
    
    /* 覆盖写法 */
    int partition(vector<int>& nums, int lo, int hi) {
    	int pivot = nums[lo];
    	int i = lo, j = hi - 1;
    	while(i < j) {
    		while(nums[j] > pivot && i<j) --j;
    		nums[i] = nums[j];
    		while(nums[i] <= pivot && i<j) ++i;
    		nums[j] = nums[i];
    	}
    	nums[j] = pivot;
    	return j;
    }
    #endif
    
    /*双下标写法*/ 
    int partition(vector<int>& nums, int lo, int hi) {
    	int i = lo, j = lo + 1;
    	int pivot = nums[lo];
    	while(j < hi) {
    		if(nums[j] < pivot) swap(nums[j], nums[++i]);
    		++j;
    	}
    	swap(nums[lo], nums[i]);
    	return i;
    }
    
    void quickSort(vector<int>& nums, int lo, int hi) {
    	if (lo >= hi) return;
    	int index = partition(nums, lo, hi);
    	quickSort(nums, lo, index);
    	quickSort(nums, index + 1, hi);
    }
    
    int main() {
    	vector<int> nums{3,4,2,1,6,7,4};
    	quickSort(nums, 0, nums.size());
    	for(auto& i: nums)
    		cout<<i<<endl;
    	return 0;
    }
    
    

    前2种写法注意while循环里面--j和++i的顺序不能倒过来。
    通过--j退出时,j指向的元素必定可以和pivot交换,通过++i退出就不一定了。

  • 相关阅读:
    与您分享
    与您分享
    与您分享
    与您分享
    与您分享
    分享:PythonSIP 4.14.2 发布
    与您分享
    编码
    分享:C++十种方法"Hello World"
    与您分享
  • 原文地址:https://www.cnblogs.com/pusidun/p/13207918.html
Copyright © 2011-2022 走看看