LeetCode 215 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.


意思:对给定的数组中找到第k大的数,

注意:这里是因为题目中给定了条件就是该数组中至少含有1个元素,若没有这个条件应该考虑为空的情况

思路:对数组从大到小排序,返回第k-1索引位置的元素。注意这里是k-1,因为数组是从0开始的。

        这里首先使用了库里的排序,有一个技巧改排序算法默认是从小到大,可以使用lamda表达式或者仿函数来修改从大到小的排序。

有一个更加简单的方法就是使用反向迭代器即可。之后我会手写快排

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.rbegin(), nums.rend());
        return nums[k-1];
    }
};

二、手写普通快速排序


核心思路就是partition部分。

// 对arr[l...r]部分进行partition操作
// 返回p,使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
int parttion(vector<int> &nums, int l, int r)
{
	//取出该区间的第一个元素v,以v为分界点,左边nums[l+1```j] < v   右边nums[j+1```i) > v
	int v = nums[l];           
	int j = l;
	// arr[l+1...j] < v ; arr[j+1...i) > v
	for (int i = j + 1; i <= r;i++)
	{
		if (nums[i]<v)
		{
			swap(nums[i], nums[j + 1]);
			j++;
		}
	}
	swap(nums[j], nums[l]);  //将nums[l]找到合适的位置
	return j;
}
// 对arr[l...r]部分进行快速排序
void QuickSort(vector<int> &nums, int l, int r)
{
	if (l >= r)
	{
		//递归终止的条件
		return;
	}
	int p = parttion(nums,l,r);  //将第一个元素找到合适的位置
	QuickSort(nums, l, p - 1);
	QuickSort(nums, p + 1, r);
}
自己写的快排速度就是不行,原因在于二叉树的平衡度性,高度可能比logn还要高,O(nlogn)最差的情况下会退化到O(n^2)会再次改进

三、随机化快速排序


针对有序的输入,普通快排会退化为O(n^2)的算法。改进的地方就是把数组之前左侧的标定改为数组内随机的元素。标红为改进处,这个改进速度一下上去

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        srand(time(NULL));
        QuickSort(nums,0,nums.size()-1);
        return nums[k-1];
    }
        int partition(vector<int> &nums, int l, int r)
    {
    	swap(nums[l], nums[rand() % ((r - l + 1)) + 1]);
        int v = nums[l];
    	int j = l;
    	for (int i = l+1; i <= r;i++)
    	{
    		if (nums[i] > v)
    		{
    			swap(nums[i], nums[j+1]);
    			j++;
    		}
    	}
    	swap(nums[l], nums[j]);
    	return j;
    }
    void QuickSort(vector<int> &nums, int l, int r)
    {
    	if (l>=r)
    	{
    		return;
    	}
    	int p = partition(nums,l,r);
    	QuickSort(nums, l, p - 1);
    	QuickSort(nums, p + 1, r);
    }
};

四、双路快排

针对有大量重复元素的数组进行随机化快排,最终随机化快排会退化成O(n^2)的算法,是因为树的高度左右两边极其不均衡,在随机化快排中将等于标定的元素放在了>v一侧也就是右侧,这样就会在右侧不平衡,造成高度高于logn,双路快排这样就能将重复的元素比较均衡的放在两侧

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        if(nums.size() == 1)
        {
            return nums[0];
        }
        srand(time(NULL));
        QuickSort(nums,0,nums.size()-1);
        return nums[k-1];
    }
    
    int partition2(vector<int> &nums, int l, int r)
    {
    	//取出该区间的第一个元素v,以v为分界点,左边nums[l+1```j] < v   右边nums[j+1```i) > v
    	//nums[rand() % ((r - l + 1)) + 1];  //随机生成一个索引,意思就是以前是最左侧的元素作为标定,现在是数组内的随机元素作为标定
    	swap(nums[l], nums[rand() % ((r - l + 1)) + l]);
    	int v = nums[l];
    	int j = r;
    	// arr[l+1...i) <= v; arr(j...r] >= v注意条件区别于partition
    	int i = l + 1;
    	while (true)
    	{
//这里要注意关于重复数据处理的边界巧妙性
        /*
            arr[i] < v;当arr[i] >= v不会进入循环
            arr[j] > v;当arr[j] <= v不会进入循环
            所以当两路都有数据等于v的时候,不会进入循环,直接i++,j--
            
            当左边一路有大于v的元素,需要交换到右边一路
            当右边一路有小于v的元素,需要交换到左边一路,
        */
               while (i <= r/*注意边界*/&&nums[i]>v)
    		{
    			i++;
    		}
    		while (j >= l + 1/*注意边界*/ && nums[j]<v)
    		{
    			j--;
    		}
    		if (i>j)
    		{
    			break;
    		}
    		swap(nums[i],nums[j]);
    		i++;
    		j--;
    	}
    	swap(nums[j], nums[l]);
    	return j;
    }

    void QuickSort(vector<int> &nums, int l, int r)
    {
    	if (l>=r)
    	{
    		return;
    	}
    	int p = partition2(nums,l,r);
    	QuickSort(nums, l, p - 1);
    	QuickSort(nums, p + 1, r);
    }
};

五、三路快排



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值