[LeetCode] Median of Two Sorted Arrays 解题报告

—— write for my baby, mua


[题目]

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5


[中文翻译]

给定两个有序的数组nums1nums2,数组大小分别为m、n。

找到两个数组的中位数。时间复杂度需要满足O(log(m+n))。

例子 1:

nums1 = [1, 3]
nums2 = [2]

中位数为 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

中位数为 (2 + 3)/2 = 2.5

[解题思路]

O(m+n)

直接的想法就是merge。循环地比较队顶元素,弹出小的,直到获得中位数。

O(log(m+n))

merge的算法,每次弹出的元素,是一个有序的序列,我们在获得中位数的同时,也将之前的元素排了序,但我们实际上只需要获得中位数,因此merge算法是有冗余的,也就是有多余的比较的。

要取得中位数,实际上就是需要获得第(m+n)/2小的数字,所以我们的目的,就是剔除前(m+n)/2-1小的数字,merge的问题在于,每次只弹出了一个元素,因此我们考虑,每次尽可能多地剔除元素。

设需要获得第k小的元素,剔除前k-1个元素。实际上,我们最多一次可以剔除k/2个元素。比较nums1[k/2]和nums2[k/2],如果nums1[k/2]较小,则可剔除nums1的前k/2个元素;否则剔除nums2的前k/2个元素。

可以证明,第k小的元素一定不在被剔除的k/2个元素中,因为在nums1[1..k/2]和nums2[1..k/2]一共k个元素中,如果存在第k小的元素,则一定是这k个元素中最大的一个,而剔除的规则保证了最大的一个是被保留的。

剔除完k/2个元素后,问题就转化为,在剩下的序列中,求第(k-k/2)小的元素,可见可以循环/递归地解决。

直到最后,需要求第1小的元素,就不需要剔除元素了,递归结束。时间复杂度为O(logk)


[C++代码]

class Solution {
public:
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
		double res;
		int i = -1, j = -1;
		int index;

		if (0 == (nums1.size() + nums2.size()) % 2)
			index = (nums1.size() + nums2.size()) / 2;
		else
			index = (nums1.size() + nums2.size()) / 2 + 1;

		while (index > 1) {
			int step = index / 2;

			if (i + 1 >= nums1.size()) {
				j += index - 1;
				break;
			}

			if (j + 1 >= nums2.size()) {
				i += index - 1;
				break;
			}

			if (i + step >= nums1.size())
				step = nums1.size() - 1 - i;
			if (j + step >= nums2.size())
				step = nums2.size() - 1 - j;

			if (nums1.at(i + step) < nums2.at(j + step))
				i = i + step;
			else
				j = j + step;

			index -= step;
		}

		i++; j++;

		if (0 == (nums1.size() + nums2.size()) % 2) {
			if (i >= nums1.size())
				res = nums2.at(j++);
			else if (j >= nums2.size())
				res = nums1.at(i++);
			else if (nums1.at(i) < nums2.at(j))
				res = nums1.at(i++);
			else
				res = nums2.at(j++);

			if (i >= nums1.size())
				res += nums2.at(j);
			else if (j >= nums2.size())
				res += nums1.at(i);
			else
				res += (nums1.at(i) < nums2.at(j)) ? nums1.at(i) : nums2.at(j);

			res /= 2;
		}
		else {
			if (i >= nums1.size())
				res = nums2.at(j++);
			else if (j >= nums2.size())
				res = nums1.at(i++);
			else if (nums1.at(i) < nums2.at(j))
				res = nums1.at(i++);
			else
				res = nums2.at(j++);
		}

		return res;
	}
};

[注意]

代码16行和21行,不能写成i >= nums1.size() - 1,原因是nums1.size()是size_t一般为unsigned int类型(反正是个无符号整,因为size不可能为负),在比较的时候,i会被自动转换成unsigned int进行比较,i的初始值为-1,转换成unsgined int之后是最大的无符号整型,因此不会达到我们逻辑上的目的。而在我们的程序中i+1>=0,因此没有问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值