liuxuhelloworld's notebook

题目链接

https://leetcode.cn/problems/median-of-two-sorted-arrays/

解答过程

这个题目本身并不难理解,给定两个有序数组,求这两个有序数组一起构成的集合的中位数。如果是给定一个有序数组,我们很容易得到这个有序数组的中位数,只需要根据数组长度计算中位数的下标,然后直接读取对应的数据即可。那么显然,这个题目我们可以先合并两个有序数组,然后就可以很方便地计算中位数了。合并有序数组并不复杂,和合并有序链表的思路类似,代码还简单很多。合并有序数组这种解法,显然时间复杂度是O(N)的,空间复杂度也是O(N)。一种优化方式是不做真正的合并,而是在模拟合并的过程中计数,当遍历到中位数的位置时,模拟合并就结束了。这种优化方式的时间复杂度一样还是O(N)的,主要是空间复杂度可以降低到O(1)。

考虑到这个题目的难度是困难,题目里也明确要求时间复杂度为O(log(N)),那么显然上面两种解法都不满足题目要求。那么如何才能达到O(log(N))的时间复杂度呢?有序数组,O(log(N)),如果有经验或者好直觉的话,可以想到,应该从二分法的角度入手。我们可以先翻译一下我们的问题:给定两个有序数组,我们需要以O(log(N))的时间复杂度得到这两个有序数组的第K小元素。既然是从二分法入手,那么我们可以再翻译一下我们的问题:如何快速排除N=K/2个元素。既然两个数组都是有序的,那么我们可以分别取这两个数组的前N个元素,那么显然它们一起构成了这两个有序数组的最小2N个元素(2N<=K,因为N=K/2是整数除法)。换句话说,第K小元素要么是这2N个元素的最大值,要么不在这2N个元素中。我们可以比较这两个长度为N的子数组的最大元素,对于较小的那个,连同它以及它前面这N个元素,我们可以直接排除,因为第K小的元素不会在这个子数组中。这样,我们不就是快速排除了N=K/2个元素么?当然,这里面还有一些边界问题需要注意,比如两个数组可能一个已经为空、比如取第1小的元素等

这个题目是在看了官方题解以后写出来的,甚至不是当时就写出来的,而是再三思考加尝试以后才写出来。另外,我觉得相比官方题解的代码,我这里计算new index的写法更好理解[狗头]

	public double findMedianSortedArrays(int[] nums1, int[] nums2) {
		int len1 = nums1.length;
		int len2 = nums2.length;

		if ((len1 + len2) % 2 == 0) {
			int cnt1 = (len1 + len2) / 2;
			int cnt2 = (len1 + len2) / 2 + 1;
			int val1 = findKthNumberOfTwoSortedArrays(nums1, nums2, cnt1);
			int val2 = findKthNumberOfTwoSortedArrays(nums1, nums2, cnt2);
			return (double)(val1 + val2) / 2;
		} else {
			int cnt = (len1 + len2) / 2 + 1;
			int val = findKthNumberOfTwoSortedArrays(nums1, nums2, cnt);
			return (double) val;
		}
	}

	private int findKthNumberOfTwoSortedArrays(int[] nums1, int[] nums2, int k) {
		int idx1 = 0, idx2 = 0;
		while (true) {
			if (idx1 >= nums1.length) {
				return nums2[idx2 + k - 1];
			}

			if (idx2 >= nums2.length) {
				return nums1[idx1 + k - 1];
			}

			if (k == 1) {
				return Math.min(nums1[idx1], nums2[idx2]);
			}

			int n = k/2;
			int newIdx1 = Math.min(idx1 + n - 1, nums1.length - 1);
			int newIdx2 = Math.min(idx2 + n - 1, nums2.length - 1);
			int val1 = nums1[newIdx1];
			int val2 = nums2[newIdx2];
			if (val1 <= val2) {
				k = k - (newIdx1 - idx1 + 1);
				idx1 = newIdx1 + 1;
			} else {
				k = k - (newIdx2 - idx2 + 1);
				idx2 = newIdx2 + 1;
			}
		}
	}

相似题目