有两个大小为 m 和 n 的排序数组 nums1 和 nums2 。
请找出两个排序数组的中位数并且总的运行时间复杂度为 O(log (m+n)) 。
示例 1:
这是问题,我刚开始刷leetCode还没多久,刚开始做这个题的时候,觉得真的挺难得。他的难点主要就是时间复杂度的问题。然后做了两三个小时实在做不出来我就找了看了官方给的解释,因为英语是个半吊子,理解起来蛮吃力的。查博客的话,大多只是写了个大概,对于我这个渣渣来说理解起来很吃力。所以我就想写一个更详细点的!
做这个题的时候我们要注意题目的意思:题目所给的两个数组已经排好序了,如果没注意到这点,这个题是没办法做。然后开始分析:
(1)本题的难点是要有了复杂度,也就是log(n+m) 看见log我们所能想到的肯定是用到了分冶法,不然不会出现这个玩意的。
(2)然后开始理解中位数,就是能把一个数组分成两半。也就是 左边的最大的数 小于等于 右边最小的数
接下来就可以了:暂时不考虑极端情况,假设数组A和数组B长度都大于2;
A: A[0] A[1] A[2]…A[m-3] A[m-2] A[m-1]
B: B[0] B[1] B[2]…B[n-3] B[n-2] B[n-1]
那么:分析一下, A和B的长度和起来是n+m,一般的长度就是 (n+m)/2
也就是 m/2 +n/2 那我们可以直接把 A和前半部分和B的前半部分 直接拿出来
A: A[0] A[1] A[2]… A[j-1] | A[j] …A[m-3] A[m-2] A[m-1] 将A分成了两半
B: B[0] B[1] B[2]… B[i-1] | B[i]…B[n-3] B[n-2] B[n-1] 将B分成了两半
A[j]是A的中位数,B[i]是B的中位数,这个中位数很好求的,(j=m/2 i=n/2)
然后我们将 A的前半部分和B的前半部分 合在一起,把A的后半部分和B的后半部分合在一起, 假如点半部分合起来的最大值 小于等于后半部分的最小值,那么中位数不是直接就求出了了么。用一个关系式表示:
j+i=(n+m)/2 && max(A[j-1] B[i-1]) <= min(A[j] B[i])
i和j是有关系的,这里不再讨论,看后面的关系式:要注意 A[j-1] 是一定小于 A[j]的(A和B是有序的)所以我们只需要让A[j-1] <=B[j] 就行,同理让 B[i-1] <= A[j] ,这样做的目的是什么呢?
因为实际情况肯定和我们想的不一样:
情况1:
A[j-1] > B[i] 了怎么办? 这时候我们可以理解为,A的左边有数据过大,所以我们必须把这个大数给 右边,但是这样就会产生左边的总数少了,那我们就把B右边的给左边一个就行了:
A: A[0] A[1] A[2]… A[j-2] | A[j-1] …A[m-3] A[m-2] A[m-1] j-1 | j+1
B: B[0] B[1] B[2]… B[i] | B[i+1]…B[n-3] B[n-2] B[n-1] i+1 | i-1
所以左边合起来的总是依旧等于右边合起来的总数:
同理:
B[i-1] > A[j] 就把 B[i-1]送给右边同时把A[i]送给左边就行。
A: A[0] A[1] A[2]… A[J] | A[j+1] …A[m-3] A[m-2] A[m-1] j+1 | j-1
B: B[0] B[1] B[2]… B[i-2] | B[i-1]…B[n-3] B[n-2] B[n-1] i-1 | i+1
没有第三种情况:
不可能两个条件同时不符合:因为 A[j]>= A[j-1] 如果 A[j-1] > B[i] 那么 A[j] >= A[j-1] > B[i] >=B[i-1] 所以A[j]>B[i-1]
当然如果n活着m是奇数的话,也不需要在意,因为我们要的是 ( max(left_part)+min(right_part) )/2
补充:我们是用 j来表示i的,所以m要小,为的是不让i算出了是个负数!!!
代码:
public double findMedianSortedArrays(int[] A, int[] B) {
int m = A.length;
int n = B.length;
if (m > n) { // to ensure m<=n
int[] temp = A; A = B; B = temp;
int tmp = m; m = n; n = tmp;
}
int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
while (iMin <= iMax) {
int i = (iMin + iMax) / 2;
int j = halfLen - i;
if (i < iMax && B[j-1] > A[i]){
iMin = i + 1; // i is too small
}
else if (i > iMin && A[i-1] > B[j]) {
iMax = i - 1; // i is too big
}
else { // i is perfect
int maxLeft = 0;
if (i == 0) { maxLeft = B[j-1]; }
else if (j == 0) { maxLeft = A[i-1]; }
else { maxLeft = Math.max(A[i-1], B[j-1]); }
if ( (m + n) % 2 == 1 ) { return maxLeft; }
int minRight = 0;
if (i == m) { minRight = B[j]; }
else if (j == n) { minRight = A[i]; }
else { minRight = Math.min(B[j], A[i]); }
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
public static void main(String[] args) {
int a[] = {1,2,3};
int b[] = {4,5,6,7};
Soultion soultion = new Soultion();
System.out.println(soultion.findMedianSortedArrays(a,b));
}
}
中位数:4.0
作者:qq_41014682
来源:CSDN
原文:https://blog.csdn.net/qq_41014682/article/details/79812181
版权声明:本文为博主原创文章,转载请附上博文链接!