zoukankan      html  css  js  c++  java
  • 4. Median of Two Sorted Arrays[H]两个有序数组的中位数

    题目

    There are two sorted arrays nums1 and nums2 of size m and n respectively.
    Find the midian 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.
    Example1:
      nums1 = [1, 3]
      nums2 = [2]
      The median is 2.0
    Example2:
      nums1 = [1, 2]
      nums2 = [3, 4]
      The median is (2+3)/2.0 = 2.5

    思路


    二分查找、递归法

    假设两个数组A和B中的个数都大于(frac{k}{2})个(存在某一数组个数不足(frac{k}{2})个),分别取出第(frac{k}{2})个元素(数组下标为$frac{k}{2}-$1)进行比较,此时有三种情况:

    • A[$frac{k}{2}-$1] (;)< (;) B[$frac{k}{2}-$1]
    • A[$frac{k}{2}-$1] (;)=(;) B[$frac{k}{2}-$1]
    • A[$frac{k}{2}-$1] (;)>(;) B[$frac{k}{2}-$1]

    对于第一种情况,如果A的第 (frac{k}{2}) 个元素(数组下标为 $ frac{k}{2}-1$ )比B的第 (frac{k}{2}) 个元素(数组下标为 (frac{k}{2}-1) )小,说明当A和B合并之后,A的下标从0到( (frac{k}{2}-1) )之间的数都不可能是第k大的数,即对数组cut的小了,应该增大k。如果相等,就是需要寻找的元素(第k-1个元素)。大于的情况与小于类似。奇数个就取中间的,偶数个将两个数加起来除以2.0即可。
    递归的边界条件:
    1)其中某一数组为空的话,则直接返回另一个数组下标为[k-1]的数。(见单数组寻找第k个元素)
    2)如果k=1,即查找最小值,直接比较两个数组的第1个元素(数组下标为0)即可。
    3)如果A[$frac{k}{2}-(1]=B[)frac{k}{2}-$1],只需要返回其中的一个。

    Tips


    Cut思想寻找第k个数

    通过Cut,将数组切割为左右两部分:(Left_{part}, Right_{part}),此时产生两个元素,分别是左边的最大值(L_{max})和右边的最小值(R_{min})。Cut过程中,可以Cut一个数,则这个数既属于左边,又属于右边;也可以在两个数中间Cut。

    • 单数组寻找第k个元素
      对于有序数组A,在第k个数(数组下标为k-1)cut一下,返回值(A[k-1]=L{max}),即为第k个数,该数为左边部分最大值。(k=1,2,...)

    • 双数组寻找第k个元素

    (left_{part}) (C_i) $right_{part} $
    (a_1,a_2,cdots,a_i) / (a_{i+1},a_{i+2},cdots,a_m)
    (b_1,b_2,cdots,b_j) / (b_{j+1},b_{j+2},cdots,a_n)

    定义(L_{max_1}),(L_{max_2})为Cut之后(Left_part)第1个和第2个数组的最大值,(R_{min_1}),(R_{min_2})为Cut之后(Right_{part})第1个和第2个数组的最小值。(C_1、C_2)是第1、2个数组的Cut。
    如果满足:
    1)(L_{max_1};< ;R{min_1})(L_{max_2} ; <; R_{min_2})。(这是一定满足的,因为数组有序,左边一定小于右边。)
    2)(L_{max_1};<=;R_{min_2}),且(L_{max_2};<=;R_{min_1})
    (Left_{part})全小于(Right_{part})如果左边的元素个数加起来刚好等于k,那么第k个元素就是(Max(L_{max_1},L_{max_2}))(参见单数组寻找第k个元素)。如果(L_{max_1};>;R_{min_2}),说明数组1的左边元素太多(大)了,需要减小(C_1),把(C_2)增大。同理可得(L_{max_2};>;R_{min_1}),将(C_1)增大,(C_2)减小。

    C++

    class Solution {
    public:
         double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
             
             int n1 = nums1.size();
             int n2 = nums2.size();    
             int total = n1 + n2;
             
             if(total % 2){ //如果数组加起来是奇数 
                 return findKth(nums1, 0, nums2, 0, total / 2 + 1);
             }
             else{ //如果是偶数
                 return (findKth(nums1, 0, nums2, 0, total / 2 ) + findKth(nums1, 0, nums2, 0, total / 2 + 1) )/2.0;
             }
               
         }
        
        //分割的思想寻找第k个数
        double findKth(vector<int>& nums1, int l, vector<int>& nums2, int r, int k){
            
            int n1 = nums1.size();
            int n2 = nums2.size();
            
            if(n1 - l > n2 -r ) 
                  return findKth(nums2, r, nums1, l, k); //始终保证第一个数组是个数是最少的
            
            if(n1-l == 0)
                return nums2[r + k -1];
            if(k == 1)
                return min(nums1[l], nums2[r]);
            
            int p1 = min(k/2 , n1); //保证在第一个数组内做二分查找。
            int p2 = k - p1;
            
            if(nums1[l + p1 -1] < nums2[r + p2 -1]){ //左边
                return findKth(nums1, l+p1,nums2, r,k - p1);
            }
            else if(nums1[l + p1 -1] > nums2[r + p2 -1]){ //左边数组1的个数太大
                return findKth(nums1, l,nums2, r+p2,k - p2);
            }
            else{
                return nums1[l+p1-1];
            }
        }  
    };
    

    python

    class Solution(object):
        def findKth(self, nums1, nums2,k):
            
            k = int(k)
            n1 = len(nums1)
            n2 = len(nums2)
            
            if n1 > n2: 
                return self.findKth(nums2, nums1, k)
            if n1 == 0: 
                return nums2[k - 1]
            if k == 1: 
                return min(nums1[0], nums2[0])
            p1 = int(min(k / 2, n1))
            p2 = k - p1
            if nums1[p1 - 1] <= nums2[p2 - 1]:
                return self.findKth(nums1[p1:], nums2, p2)
            else:
                return self.findKth(nums1, nums2[p2:], p1)
            
        def findMedianSortedArrays(self, nums1, nums2):
            """
            :type nums1: List[int]
            :type nums2: List[int]
            :rtype: float
            """
            n1 = len(nums1)
            n2 = len(nums2)
            total = n1 + n2
            if(total % 2):
                return self.findKth(nums1, nums2, total /2 + 1)
            else:
                return (self.findKth(nums1, nums2, total /2 )+ self.findKth(nums1, nums2, total /2 + 1))/2.0           
    

    参考

    [1] https://blog.csdn.net/hk2291976/article/details/51107778
    [2] https://leetcode.com/problems/median-of-two-sorted-arrays/solution/

  • 相关阅读:
    LeetCode 1122. Relative Sort Array (数组的相对排序)
    LeetCode 46. Permutations (全排列)
    LeetCode 47. Permutations II (全排列 II)
    LeetCode 77. Combinations (组合)
    LeetCode 1005. Maximize Sum Of Array After K Negations (K 次取反后最大化的数组和)
    LeetCode 922. Sort Array By Parity II (按奇偶排序数组 II)
    LeetCode 1219. Path with Maximum Gold (黄金矿工)
    LeetCode 1029. Two City Scheduling (两地调度)
    LeetCode 392. Is Subsequence (判断子序列)
    写程序判断系统是大端序还是小端序
  • 原文地址:https://www.cnblogs.com/Jessey-Ge/p/10991587.html
Copyright © 2011-2022 走看看