LintCode笔记(12)——第k大元素

在数组中找到第k大的元素

 注意事项

你可以交换数组中的元素的位置

样例

给出数组 [9,3,2,4,8],第三大的元素是 4

给出数组 [1,2,3,4,5],第一大的元素是 5,第二大的元素是 4,第三大的元素是 3,以此类推

挑战 

要求时间复杂度为O(n),空间复杂度为O(1)

这道题需要利用快速排序的思想,首先复习一下什么是快速排序。

快速排序算法的主要思想为以下几步:

(1)首先选中一个基准数;

(2)在数组中进行排序,使得比基准数小的全在他左边,比基准数大的全在他右边;

(3)对上面得到的左右区间分别执行(2)中操作,直到最终区间的数字只有一个为止。

下面对快速排序算法进行详细的解释:有如下所示的数组

0123456
3251803

假定我们选择数组的第0个元素作为基准数X且按从小到大的顺序进行排序,有初始时i = 0 ,j = 6,X = nums[i]

首先判断nums[j] >= X吗,如果成立,则不动他同时有j--寻找下一个,如果不成立,则nums[i] = nums[j];同时i++

然后判断nums[i] < X吗,如果成立,则不动他,同时有i++寻找下一个,如果不成立,则nums[j] = nums[i];同时j--

这样操作直到i>=j为止,此时数组中比X小的在他左边,比他大的在他右边。

然后分别对得到的左右区间如此操作,直到最后区间的大小为1为止。

这个博客对快速排序讲得很详细

具体的快速排序的代码如下所示(从小到大排序):

int quickSort(vector<int> &numList, int left, int right)
{
	if (left < right)//判断left到right的这个区间是否已经排序完成
	{
		//对left到right的这个区间进行排序
		int i = left;
		int j = right;
		int tmp = numList[left];
		while (i < j)//当i>=j时,排序完成
		{
			while (i < j && tmp <= numList[j])//从数组末尾开始找,直到找到比基准数tmp小的数
			{
				j--;
			}
			if (i < j)//判断前面的循环跳出是因为没有找到还是找到了比tmp小的数
			{
				numList[i++] = numList[j];//若找到了
			}
			while (i<j && tmp > numList[i])//从数组开头开始找,直到找到比基准数tmp大的数
			{
				i++;
			}
			if (i < j)//判断前面的循环跳出是因为没有找到还是找到了比tmp大的数
			{
				numList[j--] = numList[i];//若找到了
			}
		}
		numList[i] = tmp;
		quickSort(numList, left, i - 1);
		quickSort(numList, i + 1, right);
	}
}


说完了快速排序,那么如何解决这道题呢

对数组利用快速排序从大到小排序的思想,找到每一次快速排序时基准数的下标(基准数的下标即为排序好后该数的真实下标),直到找到下标为k-1的数为止。(具体怎么算时间复杂度我也不太清楚,还要学习,网上说这种算法的时间复杂度为O(n))

具体代码如下:

int quickSort(vector<int> &numList, int left, int right)
{
	//对left到right的这个区间进行排序
	int i = left;
	int j = right;
	int tmp = numList[left];
	while (i < j)//当i>=j时,排序完成
	{
		while (i < j && tmp >= numList[j])//注意与前面不一样
		{
			j--;
		}
		if (i < j)
		{
			numList[i++] = numList[j];
		}
		while (i<j && tmp < numList[i])//注意与前面不同
		{
			i++;
		}
		if (i < j)
		{
			numList[j--] = numList[i];
		}
	}
	numList[i] = tmp;
	return i;//返回基准数下标
}

int kthLargestElement(int k, vector<int> nums) {
	// write your code here
	if (nums.size() == 0)
		return 0;
	int left = 0;
	int right = nums.size() - 1;
	while (1)
	{
		int pos = quickSort(nums, left, right);
		if (pos == k - 1)//若找到的基准数下标为k-1,即为结果
		{
			return nums[k - 1];
		}
		if (pos > k - 1)//若找到的基准数下标比k-1大,则从其左区间中继续寻找,丢弃其右区间
		{
			right = pos - 1;
		}
		if (pos < k - 1)//若找到的基准数下标比k-1小,则从其右区间中继续寻找,丢弃其左区间
		{
			left = pos + 1;
		}
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值