【C++】【手撕】【top K】两个有序数组中第K个数据;(寻找两个正序数组的中位数)

题目描述

在这里插入图片描述


一、思路

最简单的思路就是从两个数组头/尾开始归并的计数。但是这样时间复杂度0(m+n);并不满足要求。

我们利用二分查找 log 时间复杂度的优势。只要单调就能二分

即:

  1. 寻找两个排序数组中第K个数,先从左边取K/2个数,小的那一边的k/2都不可能是第K个数了,于是排除。
  2. 更新K=k-k/2,也就是在剩下的数组中,找到第 新K的数字。
  3. 直到K==1,那么取当前还剩余的数组中开头处偏小的。

在这里插入图片描述
就像上图:

  1. 找第7个元素,那么两个指针都指向k/2 = 3 的位置。
  2. 3<4,说明B中前三个肯定不能是第7个元素。
  3. 抛掉B中前三个,我们开始在剩下的元素中,找第4个了。
  4. 3<5,说明A中前两个也肯定不是剩下的里面第4个元素。
  5. 抛掉A中前两个,我们开始在剩下的元素中,找第2个了.
  6. 4<=4,随便抛掉一个4,我们从剩下的元素中找第1个。
    10.4<9,说明我们要的中位数就是4

这么看起来是不是和最简单的归并计数下来差不多,只是每次舍弃的多了些而已。

二、难点:

1、中位数:和是奇数和是偶数怎么办

就像上面的图。13个数据,中位数就是第7个数。

如果是14个数,那么就找一下第七个数,然后再顺着找第八个数。然后取平均即可。

三、代码

class Solution {
public:
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {

		int length = nums1.size() + nums2.size();

		int k = (length+1) >> 1;
		bool first =true;
		if (length & 1)
			first = false;
		int temp,temp2=0;
		//find NO.K
		int base1 = 0, base2 = 0;
		int offset1 = 0, offset2 = 0;
		while (1)
		{
			offset1 = offset2 = (k >> 1);

			if (base1 == nums1.size())
			{
				temp = nums2[base2 + k-1];
				base2+= k ;
				break;
			}
			else if (base2 == nums2.size())
			{
				temp = nums1[base1 + k-1];
				base1+= k ;
				break;
			}
			else if (base1 + offset1 -1>= (int)nums1.size())
			{
				offset1 = nums1.size() - base1;
				offset2 = k - offset1;
			}
			else if (base2 + offset2 -1>= (int)nums2.size())
			{
				offset2 = nums2.size() - base2;
				offset1 = k - offset2;
			}

			if (k == 1)
			{
				if (nums1[base1 + offset1] <= nums2[base2 + offset2])
				{
					temp = nums1[base1 + offset1];
					base1++;
				}
				else
				{
					temp = nums2[base2 + offset2];
					base2++;
				}
					break;
			}

			if (nums1[base1 + offset1 - 1] <= nums2[base2 + offset2-1])
			{
				base1 += offset1;
				k -= offset1;
			}
			else
			{
				base2 += offset2 ;
				k -= offset2;
			}

		}
		if (length & 1)
			return temp;
		else
		{
			if (base1 == nums1.size())
			{
				temp += nums2[base2];

			}
			else if (base2 == nums2.size())
			{
				temp += nums1[base1];

			}
			else
				temp+= min(nums1[base1], nums2[base2]);
			return temp / 2.0;
		}
			
	}
};

考察的点:

  1. 二分查找
  2. 归并
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值