天天看点

LintCode 65. 两个排序数组的中位数LintCode 65. 两个排序数组的中位数

LintCode 65. 两个排序数组的中位数

题目描述

两个排序的数组A和B分别含有m和n个数,找到两个排序数组的中位数,要求时间复杂度应为O(log (m+n))。

样例:

输入:

A = [1,2,3,4,5,6]

B = [2,3,4,5]

输出:

3.5

样例:

输入:

A = [1,2,3]

B = [4,5]

输出:

3

思路

最直观的思路是就是将两个数组合并成一个数组,然后将这个数组进行排序,找到这个数组的中位数就可以。

相关代码

//这是最容易想到的思路,还可以使用其他排序方式,当然这种思路的算法复杂度为O(n^2)
void SelectSort(vector<int>&a, int n) {//选择排序
     int mix, temp;
     for (int i = 0; i<n - 1; i++){ //每次循环数组,找出最小的元素,放在前面,前面的即为排序好的
         mix = i; //假设最小元素的下标
         for (int j = i + 1; j<n; j++) //将上面假设的最小元素与数组比较,交换出最小的元素的下标
             if (a[j]<a[mix])
                mix = j;
        //若数组中真的有比假设的元素还小,就交换
         if (i != mix){
            temp = a[i];
            a[i] = a[mix];
            a[mix] = temp;
         }
    }
}

double findMedianSortedArrays(vector<int> &A, vector<int> &B){
       // write your code here
       int n = B.size();
       for (int i = 0; i < n; i++){
           A.push_back(B[i]);
       }

       int m = A.size();
       int left = 0, right = m;
       //选择排序
       SelectSort(A, m);
       double res;
       int mid = (left + right) / 2;
       if (m % 2 == 0){
          return res = (A[mid] + A[mid - 1]) / 2.0;
       }
       else{
          return A[mid];
       }
}
           

思路二

采用二分的思路来做。但是这道题难就难在要在两个未合并的有序数组之间使用二分法,这里我们需要定义一个函数来找到第K个元素,由于两个数组长度之和的奇偶不确定,因此需要分情况来讨论,对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。下面重点来看如何实现找到第K个元素,首先我们需要让数组1的长度小于或等于数组2的长度,那么我们只需判断如果数组1的长度大于数组2的长度的话,交换两个数组即可,然后我们要判断小的数组是否为空,为空的话,直接在另一个数组找第K个即可。还有一种情况是当K = 1时,表示我们要找第一个元素,只要比较两个数组的第一个元素,返回较小的那个即可。

相关代码

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
       int m = nums1.size(), n = nums2.size();
       int left = (m + n + 1) / 2, right = (m + n + 2) / 2;
       return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
 }
 
 int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
     if (i >= nums1.size()) return nums2[j + k - 1];
     if (j >= nums2.size()) return nums1[i + k - 1];
     if (k == 1) return min(nums1[i], nums2[j]);
     int midVal1 = (i + k / 2 - 1 < nums1.size()) ? nums1[i + k / 2 - 1] : INT_MAX;
     int midVal2 = (j + k / 2 - 1 < nums2.size()) ? nums2[j + k / 2 - 1] : INT_MAX;
     if (midVal1 < midVal2) {
        return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
     } 
     else {
        return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
     }
}
           

参考文档