题意分析
- 给你两个数组。
- 数组都是按照从小到达进行排序的
- 两个数组的大小相等
- 需要我们求出两个数组的上中位数
- 上中位数:假设递增序列长度为n,若n为奇数,则上中位数为第n/2+1个数;否则为第n/2个数
- 同时时间复杂度为O(logn),空间复杂度为O(1)
思路分析
- 其实稍微了解过排序算法的同学都应该知道,这个其实和排序算法里面的归并排序里面的归并的思想和类似。归并,也叫做分治思想。我们需要对数组进行排序的时候,我们先进行划分区间,将数组划分为一块一块小的区间的时候,我们就将这个数组两两进行归并,进而实现大的数组的有序。而这个题目就提供了两个有序的数组,需要合并成一个,这其实和归并的思想不谋而合了。
解法一 双指针枚举
- 我们发现,其实我们完全就可以使用两个指针跑一遍完事的。我们用两个指针,一个指向数组1,一个指向数组2,然后,比较两个之间大小,元素更小的指针进行向后移动,我们可以发现,最后在循环里面一定可以找到最终的答案,因为我们只需要找到n个数字即可。
如上图
代码如下
- 需要遍历到n个数字,时间复杂度为O(n),这个时间复杂度显然不符合题目要求。
- 只开了几个变量进行处理,空间复杂度为O(1)
class Solution {
public:
/**
* find median in two sorted array
* @param arr1 int整型vector the array1
* @param arr2 int整型vector the array2
* @return int整型
*/
int findMedianinTwoSortedAray(vector<int>& arr1, vector<int>& arr2) {
// write code here
int l=0,r=0;
int n=arr1.size();
int sum=0; // sum记录此时找到了多少个数字
while(l<n&&r<n){
// 如果数组1此时指向的数字小于数组2的,那么数组1移动
if(arr1[l]<arr2[r]){
sum++;
// 如果刚好到了n,那么直接返回
if(sum==n){
return arr1[l];
}
// 数组1指针移动
l++;
}else{
// 如果数组2此时指向的数字小于数组1的,那么数组2移动
sum++;
if(sum==n){
// 如果刚好到了n,那么直接返回
return arr2[r];
}
// 数组2指针移动
r++;
}
}
// 其实这个随便返回都可,因为肯定会在while里面返回,这个是为了防止语法错误
return arr1[n-1];
}
};解法二 二分法
二分法是在上面的这种解法里面进行优化的,我们发现,最后我们找到的数字具有单调性。我们分别对这两个数组进行二分操作,如果数组1的mid位置的数字小于数组2的mid,那么我们把数组1的左指针移动到中间,数组2的右指针移到中间。但是这里要注意,假如这个区间的长度是奇数,那么就是区间中点+1,否则就是区间中点;数组2的情况也是一样。如果此时两者的mid一样,那么合并之后这个数字的左右两边的个数一定是相等的。这个就是上中位数。否则,最后只需要返回两个数组的左指针指向的最小的那个数字就行了。因为上中位数一定小于等于下中位数。
代码如下
- 使用二分进行求解,显然时间复杂度为O(logn),符合题目要求
- 只使用了几个变量进行求解,空间复杂度为O(1)
class Solution {
public:
/**
* find median in two sorted array
* @param arr1 int整型vector the array1
* @param arr2 int整型vector the array2
* @return int整型
*/
int findMedianinTwoSortedAray(vector<int>& arr1, vector<int>& arr2) {
// write code here
int n=arr1.size();
int l1=0,r1=n-1; // 定义数组1的左右指针
int l2=0,r2=n-1; // 定义数组2的左右指针
while(l1<r1){ // 始终保持数组1的左指针小于右指针
int even=(r1-l1)%2; // 数组的长度
int mid1=(l1+r1)>>1; // 数组1的中点
int mid2=(l2+r2)>>1; // 数组2的中点
if(arr1[mid1]>arr2[mid2]){
// 如果数组1的中点大于数组2的中点,数组2的左指针右边移动,数组1的右指针左边移动
l2=mid2+even;
r1=mid1;
}else if(arr1[mid1]<arr2[mid2]){
l1=mid1+even;
r2=mid2;
}else{
// 如果区间中点一样,一定是上中位数
return arr1[mid1];
}
}
// 返回更小的那个,因为上中位数比下中位数小
return min(arr1[l1],arr2[l2]);
}
};
京公网安备 11010502036488号