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

来源:互联网 发布:信捷plc编程软件下载 编辑:程序博客网 时间:2024/06/06 00:18


题目出处: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
原创粉丝点击