leetcode - Median of Two Sorted Arrays

There are two sorted arrays A and B 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)).

 

找到两个有序数组的中位数(media),可以认为排序是从小到大的

先说下什么是中位数,如果元素数目是奇数,则是中间那个数,如果元素数目是偶数,则是中间两个数的平均值

这道题很容易的联想到归并的思路,用两个变量a和b从下标0开始分别去遍历A和B,较小的那个数的下标递增,直到遍历次数到达某个指定值(即中位数在整个序列中的位置排名),便找到了中位数,这个算法的时间复杂度是O(n+m)

代码:

 1 class Solution {
 2 public:
 3     double findMedianSortedArrays(int A[], int m, int B[], int n) {
 4         int total = m + n;
 5         int middle = total / 2 + total % 2;
 6         int count = 0;    
 7         int a = 0;
 8         int b = 0;
 9         int find = 0;
10 
11         while (count != middle && a < m && b < n)
12         {
13             if (A[a] < B[b])
14             {
15                 find = A[a];
16                 ++a;
17             }
18             else
19             {
20                 find = B[b];
21                 ++b;
22             }
23             ++count;
24         }
25 
26         while (count != middle && a < m)
27         {
28             find = A[a];
29             ++a;
30             ++count;
31         }
32 
33         while (count != middle && b < n)
34         {
35             find = B[b];
36             ++b;
37             ++count;
38         }
39 
40         if (total & 0x1) //奇数
41         {
42             return find;
43         }
44         else
45         {
46             if (a < m && b < n)
47             {
48                 find += A[a] < B[b] ? A[a] : B[b];
49                 return (double)find / 2;
50             }
51             if (a < m)
52             {
53                 return (double)(find + A[a]) / 2;
54             }
55             if (b < n)
56             {
57                 return (double)(find + B[b]) / 2;
58             }
59         }
60 
61         return -1;
62     }
63 };

但是,题目要求时间复杂度O(log(m+n)),log级别的查找很容易想到二分,关于利用二分法来查找中位数,可以看看这篇文章:http://blog.csdn.net/yutianzuijin/article/details/11499917/,将题目转化为查找第k小的数(这道题里,第k小的数是中位数),我把思路注释在代码里了,可以结合代码看看:

 1 class Solution {
 2 public:
 3     double findMedianSortedArrays(int A[], int m, int B[], int n) {
 4         int total = m + n;
 5         if (total & 0x1) //奇数
 6         {
 7             return findMedian(A, m, B, n, (m + n) / 2 + 1);
 8         }
 9         else
10         {
11             return (findMedian(A, m, B, n, (m + n) / 2 + 1) + findMedian(A, m, B, n, (m + n) / 2)) / 2;
12         }
13     }
14     //查找第k小的数
15     double findMedian(int A[], int m, int B[], int n, int k)
16     {
17         if (m > n) //始终保持A的长度不大于B
18         {
19             return findMedian(B, n, A, m, k);
20         }
21         if (m == 0) //若A的长度为0,则直接返回B的第k个数
22         {
23             return B[k - 1];
24         }
25         if (k == 1) //k已无法再分,返回A[0]和B[0]中较小者
26         {
27             return A[0] < B[0] ? A[0] : B[0];
28         }
29         //因为m不大于n,所以可能有m<(k/2),此时选取A的最后一个数即可
30         int a = k / 2 > m ? m : k / 2;
31         //选取B的前k-a个数,使得a+b=k,以便之后的比较可以删除a个或b个数(约k/2个),达到log级别的查询
32         int b = k - a;
33 
34         if (A[a - 1] < B[b - 1]) //说明A[a - 1]到A[0]的数都在第k小的数之前,可以将它们都去除
35         {
36             return findMedian(A + a, m - a, B, n, k - a);
37         }
38         else if(A[a - 1] > B[b - 1]) //道理同上
39         {
40             return findMedian(A, m, B + b, n - b, k - b);
41         }
42         else //说明A[a - 1]或B[b - 1]刚好是第k小的数,返回即可
43         {
44             return A[a - 1];
45         }
46     }
47 };

精髓在于findmedian这个方法,查找第k小的数,可设A的长度不大于B的长度(如果A的长度大于B的长度,交换一下即可),在A中取第k/2个数(因为A的长度是较小的,可能不够k/2,那么此时取最后一个数即可),在B中取第k - a个数,通过比较这两个数,可以每次去除a个数或b个数(约为k/2个数),直到递归的基本条件,这里面的一些思路算法我也还无法讲得很清楚,如果没太明白可以多看看其他文章

posted on 2014-09-24 15:11  laihaiteng  阅读(130)  评论(0编辑  收藏  举报

导航