[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,因此沒有問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章