赞
踩
时隔许久,我又回来了。
题目:给定两个大小分别为m和n的正序(从小到大)数组nums1和nums2。请你找出并返回这两个正序数组的中位数。
要求算法的时间复杂度为O(log(m+n))。
示例1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
题目链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
C++实现
方法一:
很朴素的想法,通过归并排序的思路将两个正序数组合并为一个数组data,再根据data所含个数的奇偶性分别返回相应的结果。
时间复杂度O(m+n)
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { //新开辟数组data,记录nums1和nums2合并后的有序数组 vector<int> data; int i=0,j=0; while(i<nums1.size()&&j<nums2.size()) { if(nums1[i]<nums2[j]){ data.push_back(nums1[i++]); } else{ data.push_back(nums2[j++]); } } while(i<nums1.size()) { data.push_back(nums1[i++]); } while(j<nums2.size()) { data.push_back(nums2[j++]); } double ret=0; //待返回的中位数 if(data.size()%2==1) { ret=data[data.size()/2]; } else{ ret=(data[(data.size()-1)/2]+data[(data.size()-1)/2+1])/2.0; } return ret; } };
方法二:
借鉴官方题解,通过二分查找实现。时间复杂度O(log(m+n))。
m+n是奇数时,中位数是两个正序数组中的第(m+n)/2+1个元素(从1开始数);
m+n是偶数时,中位数是两个正序数组中的第(m+n)/2和第(m+n)/2+1个元素的平均值。
因此主要问题是实现找到两个正序数组的第k个元素的函数findKth(),如下所示:
使用index1和index2分别记录删除部分元素后,num1和num2下标的偏移量。初始为0。
比较num1[k/2-1]和num2[k/2-1],以num1[k/2-1]<num2[k/2-1]为例,反之同理。num1[k/2-1]左侧共k/2-1个元素,即使num2[k/2-1]左侧的k/2-1个元素均全部小于num1[k/2-1]时,num1[k/2-1]名次取到最大为k-1,无法成为第k个元素。因此num1[k/2-1]及其左侧的元素均可排除,即nums1[0]到nums1[k/2-1]。k相应减少k/2个元素。
由于存在删除元素后考虑位置发生偏移,因此需要加上相应的基准index1和index2。
要注意可能存在index*+k/2-1下标越界的情况:nextIndex1=min(index1+k/2-1,m-1)。如果某一个数组越界,直接返回另一个数组中的第k个元素。
示例分析:
num1={1,3,4,9}
num2={1,2,3,4,5,6,7,8,9}
找第k=(4+9)/2+1=7个元素
index1=0,index2=0,比较下标为k/2-1=2的两个数:num1[2]=4>num2[2]=3,于是num2[index2]到num2[index2+k/2-1]范围内的元素被排除。修改index2和k:index2=3,k=k-k/2=4。index1=0。
比较num1[index1+k/2-1]=num1[1]和num2[index2+k/2-1]=num2[4]:num1[1]=3<num2[4]=5。于是num1[0]到num1[1]范围元素被排除。修改index1和k:index1=2,k=k-k/2=2。index2=3。
比较num1[index1+k/2-1]=num1[2]和num2[index2+k/2-1]=num2[3]:num1[2]=4<num2[3]=4。于是num1[2]到num1[2]范围元素被排除。修改index1和k:index1=3,k=k-k/2=1。index2=3。
k==1时,返回num1[index1]和num2[index2]中较小的一个,结束循环。这里返回4即为所求第7个数。
代码:
class Solution { public: int findKth(vector<int>& nums1, vector<int>& nums2,int k) //找到两个正序数组的第k个元素 { int m=nums1.size(); int n=nums2.size(); int index1=0,index2=0; //index1和index2分别记录num1和num2各自的偏移量 while(1) { //边界情况 if(index1==m){return nums2[index2+k-1];} //num1越界 if(index2==n){return nums1[index1+k-1];} //num2越界 if(k==1){return min(nums1[index1],nums2[index2]);} //正常情况 int nextIndex1=min(index1+k/2-1,m-1); //下一个比较值下标,注意越界时删除元素变少 int nextIndex2=min(index2+k/2-1,n-1); if(nums1[nextIndex1]<=nums2[nextIndex2]) { k-=(nextIndex1-index1+1); //修改k index1=nextIndex1+1; //删除num1中元素,修改index1 } else{ k-=(nextIndex2-index2+1); //修改k index2=nextIndex2+1; //删除num2中元素,修改index2 } } } double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m=nums1.size(); int n=nums2.size(); if((m+n)%2==1){return findKth(nums1,nums2,(m+n)/2+1);} else{return (findKth(nums1,nums2,(m+n)/2)+findKth(nums1,nums2,(m+n)/2+1))/2.0;} } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。