题目描述:
标签:数组 二分查找 分治算法
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?
代码:
一、方法一:先合并再查找中位数
思路分析:时间复杂度O(m+n)
① 首先新建一个数组nums,用来存储合并后的数组。
②判断nums1和nums2数组是否有空数组,如果有,则返回非空数组的中位数。
③如果nums1和nums2数组都为非空数组,则设置三个指针count,i,j分别指向nums、nums1、nums2。每次比较nums1[i]和nums2[j]的值,将较小的值放入nums数组。
同时需要注意数组长度不等长的情况,所以要先判断是否有数组已经遍历结束,如果有,则将未遍历结束的数组剩余元素依次添加到nums。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int[] nums;
int m = nums1.length;
int n = nums2.length;
nums = new int[m + n];
//如果nums1数组为空
if(m == 0){
if(n % 2 == 0){//长度为偶数
return (nums2[n/2-1] + nums2[n/2]) / 2.0;
}else{//长度为奇数
return nums2[n/2];
}
}
//如果nums2数组为空
if(n == 0){
if(m % 2 == 0){
return (nums1[m/2-1] + nums1[m/2]) / 2.0;
}else{
return nums1[m/2];
}
}
//先合并两个数组
int count = 0;//指向nums的下标
int i = 0;//指向nums1的下标
int j = 0;//指向nums2的下标
while(count != (m + n)){
//如果nums1数组已经遍历结束
if(i == m){
while(j != n){
nums[count++] = nums2[j++];
}
break;
}
//如果nums2数组已经遍历结束
if(j == n){
while(i != m){
nums[count++] = nums1[i++];
}
break;
}
//如果nums1和nums2遍历都未完成
if(nums1[i] < nums2[j]){
nums[count++] = nums1[i++];
}else{
nums[count++] = nums2[j++];
}
}
if((m+n) % 2 == 0){
return (nums[(m+n)/2-1] + nums[(m+n)/2]) / 2.0;
}else{
return nums[(m+n)/2];
}
}
}
二、方法二:二分查找(不需要求解合并数组)
思路分析:对时间复杂度的要求有log,通常都需要用到二分查找。(详细解见官方)
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int total = m + n;
if(total % 2 == 1){
int mid = (m + n) / 2;
double median = getKthElement(nums1,nums2,mid + 1);
return median;
}else{
int mid1 = total / 2 - 1;
int mid2 = total / 2;
double median = (getKthElement(nums1,nums2,mid1 + 1) + getKthElement(nums1,nums2,mid2 + 1)) / 2.0;
return median;
}
}
public int getKthElement(int[] nums1,int[] nums2,int k){
int len1 = nums1.length;
int len2 = nums2.length;
int index1 = 0;
int index2 = 0;
int kthElement = 0;
while(true){
//边界条件
if(index1 == len1){
return nums2[index2 + k - 1];
}
if(index2 == len2){
return nums1[index1 + k -1];
}
if(k == 1){
return Math.min(nums1[index1],nums2[index2]);
}
//正常情况
int half = k / 2;
int newIndex1 = Math.min(index1 + half,len1) - 1;
int newIndex2 = Math.min(index2 + half,len2) - 1;
int val1 = nums1[newIndex1];
int val2 = nums2[newIndex2];
if(val1 <= val2){
k -= (newIndex1 - index1 + 1);
index1 = newIndex1 + 1;
}else{
k -= (newIndex2 - index2 + 1);
index2 = newIndex2 + 1;
}
}
}
}