4.求两个已经排好序的数组的中位数


题目出处:https://leetcode.com/problems/median-of-two-sorted-arrays/

两个已经排好序的数组:nums1 和 nums2, 他们的长度分别是m和n. 求这两个数组的中位数。 要求时间复杂度是O(log(m+n)).

数组的中位数: 就是一排数据从小到大排列后,中间的那个数。 比如 [1, 2, 3, 4, 5], 那中位数就是3. 而 [1, 2, 3, 4, 5,6]的中位数就是 3, 4. 题目要求返回(3+4)/2 =3.5

分析: 

1. 如果是一个数组,直接求解好求,直接长度length/2 可直接索引到中位数的位置, 这样可直接求解。

2. 不能合并数组,合并数组的时间复杂度为O(m+n). 与题目要求的O(log(m+n))符.

3. 不考虑复杂度时,最简单的方法是从左到右逐个移动,可很简单的实现快速找到中位数的位置,时间复杂度O((m+n)/2)., 后面会展示算法(算法1)

4. 时间复杂度O(log(m+n))的算法,让我想到二分查询算法, 细想下这问题与方法很像,都是查询,二分查询查询的某个值,而本算法查询的是中位数的位置。 所以决定模仿二分查询来解决这个问题。


算法1 顺序查询法

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int length = nums1.size() + nums2.size();
        if(length == 0) return 0; 
        //计算中间数开始的位置索引, 代表需要移动的步数据
        int target = length/2; 
        if(length % 2 == 0){
            target-=1;
        }
        
        int index1 = 0, index2 = 0;
        int lastMove = 0;
        while(index1 < nums1.size() && index2 < nums2.size()){
            if(index1 + index2 > target)break;
            if(nums1[index1] >= nums2[index2])
                lastMove = nums2[index2++]; 
            else  
                lastMove = nums1[index1++];
        }
        //中位数在某个列表中
        if(index1 + index2 <= target){
            int move = target-index1 - index2; //还要移动的步数
            if(index1 < nums1.size()){
                index1 += move;
                lastMove = nums1[index1++];
            }else{
                index2 += move;
                lastMove = nums2[index2++];
            }
        }
         
        if(length % 2 == 1) return lastMove;
         int second = 0;
         if(index1 >= nums1.size()) second = nums2[index2];
         else if(index2 >= nums2.size()) second = nums1[index1];
         else second = nums1[index1] > nums2[index2] ? nums2[index2] : nums1[index1];
         
        return (lastMove + second)/2.0;
    }

算法2 二分查询法

算法简述:

1. 先计算需要移动的数:less

2. 两个数组同时移动 less/2个数(如果不够, 需要做相应调整)的值分别是data1, data2

3. data1 == data2, 则找到位置

4. data1 != data2, 则移动相应的步少, 同步减少 less的值。

循环结束标志: 

less==0, 说明已经移动到中位数位置

有某个数组已经移动到最末,即begin==end. 则在单数组中移位less,就可得到中位数据位置

代码:

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2){
    if(nums1.size() == 0 && nums2.size() == 0) return 0; 
    int length = nums1.size() + nums2.size();
    int less = length>>1; 
    if(length%2 == 0){less -= 1;}

     int begin1 = 0, end1 = nums1.size();
     int begin2 = 0, end2 = nums2.size();
      while(1){

        //检查是否已经结束
        if(less == 0 || begin1 == end1 || begin2 == end2){ 
            if(begin1 == end1)
                return (length % 2 != 0)  ?  nums2[begin2+less] : (nums2[begin2+less] + nums2[begin2+less+1])/2.0; 
            if(begin2 == end2)
                 return (length % 2 != 0)  ?  nums1[begin1+less] : (nums1[begin1+less] + nums1[begin1+less+1])/2.0;
            
            //获取第一个数字
            int first = 0;
            if(nums1[begin1] > nums2[begin2]) first = nums2[begin2++];
            else first = nums1[begin1++];
            //
            if(length % 2 != 0) return first;
            int second = 0;
            if(begin1 == end1) second = nums2[begin2];
            else if(begin2 == end2) second = nums1[begin1];
            else second = nums2[begin2] > nums1[begin1] ? nums1[begin1]: nums2[begin2];
            return (first + second)/2.0;
        }

        int mid1 = begin1 + less/2;
        int mid2 = begin2 + less/2;
        if(mid1 >= end1){
            mid1 = end1 - 1;
            mid2 = begin2 + less - end1 + begin1;
        }
        else if(mid2 >= end2){
            mid2 = end2 - 1;
            mid1 = begin1 + less - end2 + begin2;
        }
        if(nums1[mid1] == nums2[mid2]){
            less -= mid2 - begin2 + mid1 - begin1;
            begin2 = mid2;
            begin1 = mid1;
            if(less > 0){less--; begin1++;} 
        }
        else if(nums1[mid1] > nums2[mid2]){
            if(mid2 > begin2){
                less -= mid2 - begin2;
                begin2 = mid2;
            }
            else{less-=1; begin2+=1;}
        }
        else{
            if(mid1 > begin1){
                less -= mid1 - begin1;
                begin1 = mid1;
            }
            else{less-=1; begin1+=1;}
        }
      }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是位数问题的分治法伪代码: ``` def findMedianSortedArrays(nums1, nums2): # 计算两个数组的长度 m, n = len(nums1), len(nums2) # 确保 nums1 的长度小于等于 nums2 的长度,方便后面的处理 if m > n: nums1, nums2, m, n = nums2, nums1, n, m # 初始化左边界和右边界 imin, imax, half_len = 0, m, (m + n + 1) // 2 while imin <= imax: # 分别计算 nums1 和 nums2 的间位置 i = (imin + imax) // 2 j = half_len - i # 如果 i 和 j 不在边界上,比较两个间位置的值 if i < m and nums2[j-1] > nums1[i]: imin = i + 1 elif i > 0 and nums1[i-1] > nums2[j]: imax = i - 1 else: # 如果 i 和 j 已经在边界上,或者两个间位置的值满足条件 # 计算左半部分的最大值和右半部分的最小值 if i == 0: max_left = nums2[j-1] elif j == 0: max_left = nums1[i-1] else: max_left = max(nums1[i-1], nums2[j-1]) if (m + n) % 2 == 1: # 如果数组的长度是奇数,直接返回左半部分的最大值 return max_left if i == m: min_right = nums2[j] elif j == n: min_right = nums1[i] else: min_right = min(nums1[i], nums2[j]) # 如果数组的长度是偶数,返回左半部分的最大值和右半部分的最小值的平均值 return (max_left + min_right) / 2.0 ``` 假设要两个已经数组 `nums1` 和 `nums2` 的位数,可以先计算出两个数组的长度 `m` 和 `n`,然后通过比较两个数组间位置的值来缩小位数所在的范围。 具体来说,假设 `i` 是 `nums1` 的间位置,`j` 是 `nums2` 的间位置,如果 `nums1[i-1]` 小于等于 `nums2[j]`,并且 `nums2[j-1]` 小于等于 `nums1[i]`,那么位数就找到了,可以直接返回;否则根据比较结果缩小位数所在的范围,继续进行二分查找。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值