力扣 215. 数组中的第K个最大元素C++代码及分析

力扣 215. 数组中的第K个最大元素

题目

给定整数数组 nums 和整数 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

分析

偷懒方法很多,可以直接sort后输出n-k位置的元素,也可以用priority_queue声明一个大顶堆弹出k-1个元素,堆顶元素即为答案。
不过这个题目主要是考察快速排序,官方题解给的比较乱,给出一个我认为看的比较懂的

代码

class Solution {
public:
	int QuickSort(vector<int> &nums, int begin, int end, int target) {
	    if (begin >= end)
	        return nums[end];
	    int i = begin;
	    int j = end;
	    int index = rand() % (end - begin);
	    swap(nums[begin], nums[begin + index]);
	    int tmp = nums[begin];
	    while (i != j) {
	        while (j > i && nums[j] >= tmp) {
	            --j;
	        }
	        while (j > i && nums[i] <= tmp) {
	            ++i;
	        }
	        if (i != j)
	            swap(nums[i], nums[j]);
	    }
	    swap(nums[begin], nums[i]);
	    if (i == target)
	        return nums[i];
	    if (target < i)
	        return QuickSort(nums, begin, i - 1, target);
	    else
	        return QuickSort(nums, i + 1, end, target);
	}
	
	int findKthLargest(vector<int> &nums, int k) {
	    return QuickSort(nums, 0, nums.size() - 1, nums.size() - k);
	}
};

时间复杂度为O(log n),因为每次只需要遍历一半的空间,另外一半不需要进行排序

代码解释及分析

代码不难懂,基本上懂了快速排序的原理都可以看懂,主要解释几个可能会产生疑惑的地方:

	    int index = rand() % (end - begin);
	    swap(nums[begin], nums[begin + index]);

因为快速排序只有随机选择基准节点时复杂度才为O(nlog n),所以这个地方需要生成随机数来负责基准节点的选取,为了代码的方便编写,随机选取了基准节点后可以直接和begin位置的节点进行交换即可,在912. 排序数组这个题目中也可以得到验证,直接选取begin位置的节点作为哨兵节点时是会进行超时的(或者运行时间会长很多),只有随机选择节点才能 通过。

为什么外层的while循环体内部还需要判断一次i != j并进行交换

	        while (j > i && nums[j] >= tmp) {
	            --j;
	        }
	        while (j > i && nums[i] <= tmp) {
	            ++i;
	        }
	        if (i != j)
	            swap(nums[i], nums[j]);

观察这段代码的两个while条件的判断,什么情况下会出现 i != j,只有当num[j] < tmp和nums[i] > tmp的时候,这个时候两个哨兵节点是还没有相交的,还需要继续走,这个时候就可以将num[i]和num[j]进行交换,那样位置i的节点就会小于tmp,同理位置j的节点会大于tmp,这个时候两个哨兵节点就可以继续往中间走了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值