有序数组a,b,找出a,b(合并为一个大的有序数组后)中第k个数

本文介绍了一种高效算法,用于在两个已排序数组合并后找到第k个数,时间复杂度为O(log(m+n))。适用于中位数查找及下中位数计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//已知有序数组a,b,长度分别为m,n。找出a,b(合并为一个大的有序数组后)中第k个数。要求时间复杂度为o(log(m+n)).
//当k = (m+n-1)/2时,若m+n为奇数,则第k个数即为中位数;若m+n为偶数,第k个数即为下中位数。
/*
#include <iostream>
#include <math.h>
using namespace std;
int select_kth_num(int a[],int b[],int m,int n, int k)
{
	int index = -1; //存放第k个数的下标
	if (k>m+n || k<1)
	{
		return -1;
	}
	else
	{
		int begin = 0;
		int end = m-1;
		int mid = (begin+end)/2;  //先在数组a里面查找;mid为下标,若m为奇数,则mid指向正中间那个数;若为偶数,mid指向的是上中位数
		// 则a中有mid个数小于a[mid]; 若a[mid]在b中刚好大于k-mid-1个数,则a[mid]为第k个数
		while (mid >= k)  // 此时a[mid]为a中至少是第k+1个数;不符合需缩小范围
		{
			end = mid-1;
			mid = (begin+end)/2;
		}
		while (begin <= end)
		{
			mid = (begin+end)/2; 
			while (mid >= k)  // 由于外层while每次结束时,begin或end有变化,再进入循环时的mid有可能大于k,因此仍需要缩小范围。
			{
				end = mid-1;
				mid = (begin+end)/2;
			}
			if (k-mid-1 == 0)
			{
				if (a[mid]<=b[k-mid-1])
				{
					return a[mid];
				}
				else
				{
					if (a[mid]>b[k-mid-1])  //说明a,b中比a[mid]小的数的总个数大于k-1个,a[mid]取大了,应该在现在的位置的左边取
					{
						end = mid - 1;
					}
					else   //说明a,b中比a[mid]小的数的总个数小于k-1个,a[mid]取小了,应该在现在的位置的右边取
					{
						begin = mid + 1;
					}

				}
			}
			else if (k-mid-1 > 0 && k-mid-1 < n)   
			{
				if (a[mid]>=b[k-mid-2]&&a[mid]<=b[k-mid-1])
				{
					return a[mid];
				}
				else
				{
					if (a[mid]>b[k-mid-1])  //说明a,b中比a[mid]小的数的总个数大于k-1个,a[mid]取大了,应该在现在的位置的左边取
					{
						end = mid - 1;
					}
					else   //说明a,b中比a[mid]小的数的总个数小于k-1个,a[mid]取小了,应该在现在的位置的右边取
					{
						begin = mid + 1;
					}

				}
			}
			else  if ( k-mid-1 == n)  //b的长度刚好等于k-mid-1
			{
				if (a[mid]>=b[n-1])  // 此时只需a[mid] >= b[n-1]即可
				{
					return a[mid];
				}
				else
				{
					begin = mid+1;
				}
			}
			else//k-mid-1 > n ,此时超过了b中的长度,说明mid取小了
			{
				begin = mid+1;
			}

		}
		//a中没有找到,则在b中找
		begin = 0;
		end = n-1;
		mid = (begin+end)/2;
		while (mid >= k)  // 此时b[mid]为b中至少是第k+1个数;不符合需缩小范围
		{
			end = mid-1;
			mid = (begin+end)/2;
		}
		while (begin <= end)
		{
			mid = (begin+end)/2; 
			while (mid >= k)  // 由于外层while每次结束时,begin或end有变化,再进入循环时的mid有可能大于k,因此仍需要缩小范围。
			{
				end = mid-1;
				mid = (begin+end)/2;
			}
			if (k-mid-1 == 0)
			{
				if (b[mid]<=a[k-mid-1])
				{
					return b[mid];
				}
				else
				{
					if (b[mid]>a[k-mid-1])  
					{
						end = mid - 1;
					}
					else   
					{
						begin = mid + 1;
					}

				}
			}
			else if (k-mid-1 > 0 && k-mid-1 < m)
			{

				if (b[mid]>=a[k-mid-2]&&b[mid]<=a[k-mid-1])
				{
					return b[mid];
				}
				else
				{
					if (b[mid]>a[k-mid-1])  
					{
						end = mid - 1;
					}
					else  
					{
						begin = mid + 1;
					}

				}
			}
			else  if ( k-mid-1 == m)  //a的长度m刚好等于k-mid-1
			{
				if (b[mid]>=a[m-1])  // 此时只需b[mid] >= a[n-1]即可
				{
					return b[mid];
				}
				else
				{
					begin = mid+1;
				}
			}
			else  //k-mid-1 > m ,此时超过了a中的长度,说明mid取小了
			{
				begin = mid+1;
			}
		}
	}
}

int  main()
{
	int a[1] = {5},b[6] = {1,2,3,4,6,7};
	int res;
	
	for (int i = 0;i < 7;i++)
	{
		res = select_kth_num(a,b,1,6,i+1);
		cout<<res<<endl;
	}
	//res = select_kth_num(a,b,8,2,4);
	//cout<<res<<endl;
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值