寻找两个正序数组的中位数

题目描述
题目链接

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000

示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

自己做题时的想法
将两个vector合并到一起+sort+返回新序列的中位数
Emmm…虽然可以过 但是没有达到题目的另一个要求 时间复杂度控制在O(log(m+n))
但是 这个做法的时间复杂度取决于排序 即O((m+n)log(m+n))
【m为第一个序列的长度 n为第二个序列的长度】

观摩了官方解答后
自己的理解
一般题目要求log的复杂度 就大概率要用到二分查找了
回到这个题目 题目求中位数
那么肯定要分为两类

  • 第一类 m+n为奇数
    此时中位数为有序序列的第(m+n+1)/2个元素

  • 第二类 m+n为偶数
    此时中位数为有序序列的第(m+n)/2和第(m+n)/2+1个元素的平均值
    转化成求两个有序序列中第k小的元素

假设两个有序数组分别是A和B 要找到第K个元素 即可转化为比较A[k/2-1]和B[k/2-1]中的较小值 对于这个求出的较小值 它最多只可能是第k-1个元素 不会是第k个元素 因此可以排除在外

分成两种情况讨论

  • 若A[k/2-1]<=B[k/2-1] 此时A[k/2-1]最多只可能是第k-2个数 所以排除A[0]到A[k/2-1]
  • 若A[k/2-1]>B[k/2-1] 此时同理 排除B[0]到B[k/2-1]

在每次这种比较后,都可以排除k/2个元素,此时搜索范围减小一半,然后再在新的数组上进行新一轮的二分查找

边界处理

  • 如果A[k/2-1] or B[k/2-1]越界 则取其对应数组的最后一个元素 此时需要根据已经排除的元素个数更新k
  • 如果一个数组为空 则直接返回另一个序列中第k个元素
  • 如果k==1 则返回两个序列首元素中的最小值

code

class Solution {
public:
	int getKthElement(const vector<int>& v1, const vector<int>& v2, int k) {
		int m = v1.size();
		int n = v2.size();
		int index1 = 0, index2 = 0;
		while (true) {
			if (index1 == m)return v2[index2 + k - 1];
			if (index2 == n)return v1[index1 + k - 1];
			if (k == 1)return min(v1[index1], v2[index2]);
			int newIndex1 = index1 + k / 2 - 1;
			int newIndex2 = index2 + k / 2 - 1;
			int p1 = v1[newIndex1];
			int p2 = v2[newIndex2];
			if (p1 <= p2) {
				k -= newIndex1 - index1 + 1;
				index1 = newIndex1 + 1;
			}
			else {
				k -= newIndex2 - index2 + 1;
				index2 = newIndex2 + 1;
			}
		}
	}
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
		int sum = nums1.size() + nums2.size();
		if (sum & 1) {
			return getKthElement(nums1, nums2, (sum + 1) / 2);
		}
		else {
			return (getKthElement(nums1, nums2, sum / 2) + getKthElement(nums1, nums2, sum / 2 + 1)) / 2.0;
		}
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值