经典算法 | 求两个排序好的数组中第k大的数优化方法

题目描述:

给定两个数组,这两个数组是排序好的,让你求这两个数组合到一起之后第K大的数。

当然你可以使用遍历,第一个数组长度为n第二个数组长度为m,那么你的方法时间复杂度为o(m +n),但是有更快的方法,时间复杂度接近于O(log(m +n)),接下来介绍这种方法。

基本思路如下,

首先取得数组a的中位数a[aMid],然后在b中二分查找a[aMid],得到b[bMid],b[bSt]到b[bMid]的数小于等于a[aMid],b[bMid+1]到b[bEd]大于等于a[aMid],这样数组a和数组b就被划分为了两个部分,第一个部分的数小于等于a[aMid],第二部分的数大于等于a[aMid],然后统计这两个区域数的个数,剩下的步骤和传统的求一个数组中的第k大的数一样。

#include<iostream>
#include <algorithm>
using namespace std; 
int a[] = { 1, 3, 5, 7 };
int b[] = { 2, 4, 6, 8 };


int theDivideFind(int num[],int left, int right, int k)
{
	if (left > right)
	{
		return right;
	}
	int mid;
	while (right >= left)
	{
		mid = (left + right) / 2;
		if (k == num[mid]) return mid;
		else if (k < num[mid])
		{
			right = mid - 1;
		}
		else
		{
			left = mid + 1;
		}
	}
	return right;
}


int main()
{
	int theResult = -1;
	int aSt, aEd;
	int bSt, bEd;
	aSt = bSt = 0;
	aEd = bEd = 3;
	int aMid = 0;
	int bMid = 0;
	int theLeftCount = 0;
	int k = 9;
	if (k <= 0 || k >= 9)
	{
		cout << -1 << endl;
		return 0;
	}

	while (1)
	{
		if (aSt == aEd && bSt == bEd)
		{
			if (k == 1) theResult = min(a[aSt], b[bSt]);
			else
			{
				theResult = max(a[aSt], b[bSt]);
			}
			break;
		}

		theLeftCount = 0;
		if (aSt <= aEd)
		{
			aMid = (aSt + aEd) / 2;
			theLeftCount += (aMid - aSt + 1);
			if (bSt <= bEd)
			{
				bMid = theDivideFind(b, bSt, bEd, a[aMid]);
				if (bMid >= bSt)
				{
					theLeftCount += (bMid - bSt + 1);
				}
			}
		}
		else
		{
			aMid = -1;
			bMid = (bSt + bEd) / 2;
			theLeftCount += (bMid - bSt + 1);
		}

		if (theLeftCount == k)
		{
			if(aSt <= aEd)
			theResult = a[aMid];
			else
			{
				theResult = b[bMid];
			}
			break;
		}
		else if(theLeftCount > k)
		{
			if (aSt <= aEd)
			{
				aEd = aMid;
			}
			if (bSt <= bEd)
			{
				bEd = bMid;
			}
		}
		else
		{
			if (aSt <= aEd)
			{
				aSt = aMid + 1;
			}
			if (bSt <= bEd)
			{
				bSt = bMid + 1;
			}
			k -= theLeftCount;
		}
	}
	cout << theResult << endl;
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值