Skip to content

Commit 18380d2

Browse files
committed
Median of Two Sorted Arrays
1 parent c70fc6f commit 18380d2

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@
1212
*.la
1313
*.a
1414
*.out
15+
16+
.c9revisions/
17+
.settings
18+
.idea/
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
@file two-sum.md
2+
@author Brian
3+
@version 1.0
4+
@date 2014-09-11
5+
6+
7+
##Median of Two Sorted Arrays [ [sourcecode](../src/MedianofTwoSortedArrays.cpp) | [problem](https://oj.leetcode.com/problems/median-of-two-sorted-arrays/) ]
8+
9+
##分析
10+
题意很简单:给定两个已排序的数组,求两个数组合并之后的数组的中位数。如果是总个数是奇数个,那就是最中间的那个,如果是偶数个,那就求最中间的两个的平均值。 要求在O(lg(m+n))时间内求出。
11+
12+
#### 方法1:排序
13+
如果不考虑时间空间限制,可以采用排序方法,将两个数组合并,然后排序,然后直接O(1)时间获得结果。
14+
排序方法的选择。如果选择快速排序,复杂度是nlogn。但最优的是选择归并排序,此处只须用到归并排序的合并步骤。边合并边计数,到 m+n/2 就答案。时间复杂度O(m+n),空间复杂度O(1).
15+
16+
#### 方法2:找第K大数法
17+
找中位数可以泛华为找第K大数,中位数就是第(m+n)/2+1大得数(奇数个数的情况)。下面讨论如何找第K大数。
18+
核心思路是竟可能快的把第K+1以后的数全部排除,剩下K个数,那两个数组中最大的就是结果。如何排除呢?
19+
20+
1. 将数目较少的数组记为A数组
21+
2. 取A中得前p个数,B中前q个数,使得p+q=k+1. 其中,p=min(k/2+1,len(A)), q = k+1-p。这样的做法的好处是,尽量使得p和q相近。
22+
3. 如果A[p-1] < B[q-1],说明B[q-1]肯定比第K大数大,因为A[0..p-1]和B[0..q-2]都小于B[q-1],总共p+q-1=k个。
23+
4. 将B[q-1...n]都去除,再从第一步1开始递归。
24+
5. 反之,如果A[p-1] > B[q-1],将A[p-1...m]都去除,从第一步1开始递归。
25+
6. 如果相等,说明第K大和第K+1大的数相等,A[p-1] ,B[q-1]其中一个第K大,另一个第K+1大。直接返回A[p-1]或者B[q-1]
26+
27+
现在考虑停止条件:
28+
29+
1. 当出现A[p-1] = B[q-1]时,直接返回结果。
30+
2. 如果A数组(较短的数组)已经为空,那么返回B[k]
31+
3. 如果m+n=k,m为A的长度,n为B的长度;说明所有的大于第k大数的都被剔除了,剩下前k大得数,返回最大值max(A[m-1],B[n-1])。
32+
33+
34+
##坑:
35+
注意p的取值,p取值时需要考虑不能使得q大于B数组的长度。p如果取min(k/2,m)的时候,就会出现死循环。例子是A={1,2,2}, B={1,2,3}.
36+
37+
1. 第一次k=3, p=1,q=3,把B的最后一个数移除
38+
2. 第二次递归:A={1,2}, B={1,2,2};k=3, p=1,q=3;将最后的B最后的2移除了。
39+
3. 然后再次递归:A=B={1,2};k=3, p=1,q=3;结果B现在只有两个数,出错了。因为p取值的时候会有判断p=min(k/2,m),使得p不会超过m,但是q没有限制,所以需要让p=min(k/2+1,m),这样q无论如何都不会出现大于n的情况。
40+
41+
证明如下:
42+
先考虑m<=k/2+1的情况,那p=m, m+n>=k+1(如果m+n==k满足终止条件就结束了) -> p+n>=k+1 -> k+1-q+n>=k+1 -> q<=n,符合条件。
43+
然后考虑m>k/2+1的情况,p = k/2+1,如果k为奇数,q=k/2, 因为程序始终保证A是较少的数组,所以n>=m>k/2+1>k/2=q;如果k是偶数,q = k/2-1 < k/2+1<m<=n。所以无论如何q<n.
44+
综上,若p=min(k/2+1, m) ,则满足q<n.
45+
46+
47+

src/MedianofTwoSortedArrays.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <iostream>
2+
3+
using namespace std;
4+
class Solution {
5+
public:
6+
// 核心思想是去掉A,B中比Kth大得所有数
7+
double findMedianSortedArrays(int A[], int m, int B[], int n) {
8+
// 如果m+n是奇数,找最中间的数
9+
if ((m + n) & 0x1) {
10+
return findKth(A, m, B, n, (m + n) / 2 + 1);
11+
} else { // 如果m+n是偶数,找最中间的两个取平均值
12+
return (findKth(A, m, B, n, (m + n) / 2) +
13+
findKth(A, m, B, n, (m + n) / 2 + 1)) / 2;
14+
}
15+
}
16+
double findKth(int A[], int m, int B[], int n, int k)
17+
{
18+
//cout<<m<<", "<<n<<endl;
19+
// 保证A数组是更短的一个
20+
if (m > n)
21+
return findKth(B, n, A, m, k);
22+
// m = 0,说明A数组空了,那么就从B中找第K大的
23+
if (m == 0)
24+
return B[k-1];
25+
26+
// 如果已经排除掉m+n-k+1个元素,现在只剩下K个,那两个数组中最大数中更大得
27+
if (m + n <= k) {
28+
return std::max(A[m-1], B[n-1]);
29+
}
30+
/**
31+
* p取其中k/2+1和m中的小值,
32+
* 注意需要取k/2+1,因为q的取值没有限制,需要保证q满足q<m
33+
* 如果p取k/2,当k为奇数时,q就可能会小于m,
34+
* 例子:A={1,2,2}, B={1,2,3}, p,q会一直是1,3,出现死循环
35+
*/
36+
int p = std::min(k/2+1, m);
37+
int q = k - p + 1;
38+
/**
39+
* 如果A[p-1] < B[q-1],
40+
* A[0..p-1]和B[0..q-2]都小于B[q-1]
41+
* 总共p+q-1=k个,所以有k个数小于B[q-1],所以B[q-1]不可能是第K大
42+
* 将B[q-1..m]删除, 递归查找A[0..m]~B[0..q-1]
43+
*
44+
* A[p-1] < B[q-1]类似
45+
*
46+
* 如果相等,说明第K大和第K+1大的数相等,A[p-1] ,B[q-1]其中一个第K大,另一个第K+1大.
47+
* 直接返回A[p-1]
48+
*/
49+
if (A[p-1] < B[q-1])
50+
return findKth(A, m, B, q-1, k);
51+
else if (A[p-1] > B[q-1])
52+
return findKth(A, p-1, B, n, k);
53+
else
54+
return A[p-1];
55+
}
56+
void p(int a[], int n)
57+
{
58+
for (int i = 0; i < n; i++) {
59+
cout<<a[i]<<" ";
60+
}
61+
cout<<endl;
62+
}
63+
};
64+
65+
66+
int main(int argc, char *argv[]) {
67+
int A[] = {1,2,2};
68+
int B[] = {1,2,3};
69+
Solution s;
70+
cout<<s.findMedianSortedArrays(A,3,B,3);
71+
}

0 commit comments

Comments
 (0)