zoukankan      html  css  js  c++  java
  • Leetcode 4. Median of Two Sorted Arrays(中位数+二分答案+递归)

    4. Median of Two Sorted Arrays
    Hard

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

    You may assume nums1 and nums2 cannot be both empty.

    Example 1:

    nums1 = [1, 3]
    nums2 = [2]
    
    The median is 2.0
    

    Example 2:

    nums1 = [1, 2]
    nums2 = [3, 4]
    
    The median is (2 + 3)/2 = 2.5
    

    思路:



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

    首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种情况:>、<和=。如果A[k/2-1]大于B[k/2-1],则A[k/2-1]小于合并之后的第k小值。

    证明也很简单,可以采用反证法。假设A[k/2-1]大于合并之后的第k小值,我们不妨假定其为第(k+1)小值。由于A[k/2-1]小于B[k/2-1],所以B[k/2-1]至少是第(k+2)小值。但实际上,在A中至多存在k/2-1个元素小于A[k/2-1],B中也至多存在k/2-1个元素小于A[k/2-1],所以小于A[k/2-1]的元素个数至多有k/2+ k/2-2,小于k,这与A[k/2-1]是第(k+1)的数矛盾。

    同理当A[k / 2 - 1] > B[k / 2 -1]时存在类似的结论

    当A[k / 2 - 1] = B[k / 2 -1]时,表示,在在A的k/2 -1之前已经有k/2 -1和数小于A[k / 2 -1],同理在B 之前也是一样的,所以此时已经找到了第k小的数,即这个相等的元素。

     1 class Solution {
     2 public:
     3     double findKth(vector<int>& nums1, int p1, vector<int>& nums2, int p2, int k){
     4         int len1 = nums1.size(), len2 = nums2.size();
     5         if(len1-p1>len2-p2){
     6             return findKth(nums2,p2,nums1,p1,k);
     7         }
     8         if(len1==p1){
     9             return nums2[p2+k-1];
    10         }
    11         if(k==1){
    12             return min(nums1[p1],nums2[p2]);
    13         }
    14         int l1 = min(k/2 + p1,len1), l2 = p2 + k - l1 + p1;;
    15         int max1 = nums1[l1-1], max2 = nums2[l2-1];
    16         if(max1==max2)  return max1;
    17         else if(max1<max2){
    18             return findKth(nums1,l1,nums2,p2,k-l1+p1);
    19         }
    20         else {
    21             return findKth(nums1,p1,nums2,l2,k-l2+p2);
    22         }
    23     }
    24     double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    25         int len1 = nums1.size(),len2 = nums2.size();
    26         if((len1+len2)%2==0){
    27             return (findKth(nums1,0,nums2,0,(len1+len2)/2)+findKth(nums1,0,nums2,0,(len1+len2+2)/2))/2;
    28         }
    29         else{
    30             return findKth(nums1,0,nums2,0,(len1+len2+1)/2);
    31         }
    32     }
    33 };
    #下面这个代码思路完全一样,加了一些注释,是来自别人的博客,附上原地址,感谢大佬:https://www.cnblogs.com/mini-coconut/p/9066508.html

    1
    double findKth(vector<int> &nums1, int i, vector<int> &nums2, int j, int k) 2 { 3 // 首先需要让数组1的长度小于或等于数组2的长度 4 if (nums1.size() - i > nums2.size() - j) { 5 return findKth(nums2, j, nums1, i, k); 6 } 7 // 判断小的数组是否为空,为空的话,直接在另一个数组找第K个即可 8 if (nums1.size() == i) { 9 return nums2[j + k - 1]; 10 } 11 // 当K = 1时,表示我们要找第一个元素,只要比较两个数组的第一个元素,返回较小的那个即可 12 if (k == 1) { 13 return min(nums1[i], nums2[j]); 14 } 15 int pa = min(i + k / 2, int(nums1.size())), pb = j + k - pa + i; 16 17 if (nums1[pa - 1] < nums2[pb - 1]) { 18 return findKth(nums1, pa, nums2, j, k - pa + i); 19 } 20 else if (nums1[pa - 1] > nums2[pb - 1]) { 21 return findKth(nums1, i, nums2, pb, k - pb + j); 22 } 23 else { 24 return nums1[pa - 1]; 25 } 26 } 27 double findMedianSortedArrays(vector<int> A, vector<int> B) { 28 int sizeA = A.size(), sizeB = B.size(); 29 if (sizeA <= 0 && sizeB <= 0) { 30 return 0; 31 } 32 int total = sizeA + sizeB; 33 if (total % 2 == 1) { 34 return findKth(A, 0, B, 0, total / 2 + 1); 35 } 36 else { 37 return (findKth(A, 0, B, 0, total / 2) + findKth(A, 0, B, 0, total / 2 + 1)) / 2; 38 } 39 }

    这里比较难理解的点是判断(nums1[pa - 1] < nums2[pb - 1])之后执行了return findKth(nums1, pa, nums2, j, k - pa + i);其实这个操作是因为目前nums1的分界线的值小于nums2分界线的值,那么证明nums1分界线以及前面的值都小于合并后的第k的值,也就是中位数。那么我们可以从这里开始,继续寻找第k-(pa-i)的值,直到两个值相等为止。

  • 相关阅读:
    Vue项目style样式层下载less-loader时候遇到的坑
    用git上传项目到github遇到的问题和解决方法
    git命令大全
    npm run dev 报错:missing script:dev
    sessionStorage缓存数据
    RTL基本知识:编译命令指定隐性线网类型
    RTL基本知识:线网的隐性声明
    物理综合:关于UDSM后端设计总结
    RTL基本知识:task和function
    物理综合:Timing_budgeting
  • 原文地址:https://www.cnblogs.com/shanyr/p/11409478.html
Copyright © 2011-2022 走看看