题目链接:
https://leetcode.com/problems/median-of-two-sorted-arrays/description/
题意理解
从两个有序数组中,找出合并数组后的中位数。
观察复杂度显然可知,是一个二分查找。
然后根据中位数的知识可知,这显然要根据两个数组的长度和进行分类讨论。
上面都是一眼能看出来的,那么怎么二分呢?
如果用非递归形式,可能会有些复杂,于是考虑一下递归怎么写。。。
想到递归的话,就可以知道,实际上主要任务是要写一个在两个有序数组中第K大的数。
然后怎么把问题规模减小从而分治呢?我们可以取 a[K/2] a [ K / 2 ] 与 b[K/2] b [ K / 2 ] 进行比较。由于LeetCode中一般有序都是说从小到大,因此如果有 a[K/2]<b[K/2] a [ K / 2 ] < b [ K / 2 ] ,那么我们可以知道有 a[i]<b[K/2](i≤K/2) a [ i ] < b [ K / 2 ] ( i ≤ K / 2 ) ,因此第K大的数肯定不会是 a[i](i≤K/2) a [ i ] ( i ≤ K / 2 ) 。于是我们只需要从 a[K/2+1] a [ K / 2 + 1 ] 开始找就好了,并且只要找 K−K/2 K − K / 2 大的数。大概思路就是这样。
我的代码
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int K = (len1 + len2) / 2;
if ((len1 + len2) % 2 == 0) {
return (findKth(nums1, 0, nums2, 0, K) + findKth(nums1, 0, nums2, 0, K + 1)) / 2.0;
} else {
return findKth(nums1, 0, nums2, 0, K + 1);
}
}
public static int findKth(int[] a, int sa, int b[], int sb, int K) {
if (sa >= a.length) {
return b[sb + K - 1];
}
if (sb >= b.length) {
return a[sa + K - 1];
}
if (K == 1) {
return Math.min(a[sa], b[sb]);
}
int ta = sa + K / 2 - 1 >= a.length ? Integer.MAX_VALUE : a[sa + K / 2 - 1];
int tb = sb + K / 2 - 1 >= b.length ? Integer.MAX_VALUE : b[sb + K / 2 - 1];
if (ta > tb) {
return findKth(a, sa, b, sb + K / 2, K - K / 2);
} else {
return findKth(a, sa + K / 2, b, sb, K - K / 2);
}
}
}
我看了一下比我快的代码,其中有些和我写的差不多,所以我是不是可以厚颜无耻的认为之后加过用例了,或者说其实算法可能会有少许常数上的差异问题不大,只要渐进复杂度差不多就行了。。。
不过我说实话的话,觉得我自己写的代码还是很好理解的,虽然细节有点多,但是感觉细节没法避免。。。