LeetCode4:两个排序数组的中位数

Posted 爆米花好美啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode4:两个排序数组的中位数相关的知识,希望对你有一定的参考价值。

问题

/*
 * @lc app=leetcode.cn id=4 lang=cpp
 *  * [4] 寻找两个有序数组的中位数
 *  * https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/
 *  * algorithms
 * Hard (33.60%)
 * Total Accepted:    37K
 * Total Submissions: 110.2K
 * Testcase Example:  '[1,3]\\n[2]'
 *  * 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
 * 
 * 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
 * 
 * 你可以假设 nums1 和 nums2 不会同时为空。
 * 
 * 示例 1:
 * 
 * nums1 = [1, 3]
 * nums2 = [2]
 * 
 * 则中位数是 2.0
 * 
 * 
 * 示例 2:
 * 
 * nums1 = [1, 2]
 * nums2 = [3, 4]
 * 
 * 则中位数是 (2 + 3)/2 = 2.5
 * 
 * 
 */

思路1:归并排序,合并有序数组,时间复杂度O(m+n),不符合要求
思路2:看到时间复杂度O(log(m+n)),首先可以想到二分法(分治思想)

  • 把找中位数转化为找第 (m+n+1)/2 和 第 (m+n+2)/2 小元素的平均(这样不用考虑奇偶的问题)

  • 二分思想设计find_kth函数 假定整体数组c中欧前k个元素一半k/2在数组a,一半k/2在数组b

    • 如果a[k/2] < b[k/2] 那么 a[0]<=a[1]<=…<=a[k/2] <= b[k/2] 且 b[0]<=b[1]<=…<=b[k/2] 说明b[k/2] 至少是c中第k小的元素,所以a[0-k/2]都小于我们的目标值,可以去掉a[0-k/2],然后在剩下的元素中找第k/2小
    • 同理如果a[k/2] > b[k/2] 所以b[0-k/2]都小于我们的目标值,可以去掉b[0-k/2],然后在剩下的元素中找第k/2小
  • 如果数组a中个数不够k/2,那么b中小于目标元素的个数一定大于k/2,所以可以去掉b中前k/2小的元素,然后在剩下的元素中找第k/2小

  • 同理如果数组b中个数不够k/2,那么a中小于目标元素的个数一定大于k/2,所以可以去掉a中前k/2小的元素,然后在剩下的元素中找第k/2小

完整代码如下

class Solution 
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) 

        int m = nums1.size();
        int n = nums2.size();
        if (nums1.empty()) 
            if (n%2 != 0)
                return 1.0*nums2[n/2];
            return (nums2[n/2]+nums2[n/2-1])/2.0;
        
        if (nums2.empty()) 
            if (m%2 != 0)
                return 1.0*nums1[m/2];
            return (nums1[m/2]+nums1[m/2-1])/2.0;
        

        int total = (m+n+1)/2;
        int total2 = (m+n+2)/2;
        // 转换为在两个有序数组中寻找第k小元素(从1计数) (m+n+1)/2  (m+n+2)/2
        return (find_kth(nums1,0,nums2,0,total)+find_kth(nums1,0,nums2,0,total2))/2.0;
    
    double find_kth(vector<int> a, int a_begin, vector<int> b, int b_begin, int k) 
        // a中无元素 b有序 直接在b中取第k小元素
        if (a_begin > a.size()-1)
            return b[b_begin+k-1];
        if (b_begin > b.size()-1)
            return a[a_begin+k-1];
        // 第1小元素 就是找ab中最小元素的最小值
        if (k == 1)
            return min(a[a_begin],b[b_begin]);
        if (a_begin+k/2-1 < a.size() && b_begin+k/2-1 < b.size())
            if(a[a_begin+k/2-1] < b[b_begin+k/2-1])
                return find_kth(a,a_begin+k/2,b,b_begin,k-k/2);
            else
                return find_kth(a,a_begin,b,b_begin+k/2,k-k/2);
        
        else if(a_begin+k/2-1 < a.size())
            return find_kth(a,a_begin+k/2,b,b_begin,k-k/2);
        else
           return find_kth(a,a_begin,b,b_begin+k/2,k-k/2);
        


以上是关于LeetCode4:两个排序数组的中位数的主要内容,如果未能解决你的问题,请参考以下文章

leetcode4. Median of Two Sorted Arrays

LeetCode4. 寻找两个有序数组的中位数

LeetCode4. 寻找两个正序数组的中位数

LeetCode4. 寻找两个正序数组的中位数

每日算法/刷穿 LeetCode4. 寻找两个正序数组的中位数(困难)

LeetCode4. 寻找两个正序数组的中位数(C++)