1、先正序归并,后寻找(合并两个数组)
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int[] nums = new int[nums1.length + nums2.length];
//nums1为空
if(nums1.length == 0){
if(nums2.length % 2 == 0){
return (nums2[nums2.length / 2 - 1] + nums2[nums2.length / 2]) / 2.0;
}else{
return nums2[nums2.length / 2];
}
}
//nums2为空
if(nums2.length == 0){
if(nums1.length % 2 == 0){
return (nums1[nums1.length / 2 - 1] + nums1[nums1.length / 2]) / 2.0;
}else{
return nums1[nums1.length / 2];
}
}
//将nums1和nums2正序归并为nums
int count = 0, i = 0, j = 0;
while(count != nums1.length + nums2.length){
if(i == nums1.length){
while(j != nums2.length){
nums[count++] = nums2[j++];
}
break;
}
if(j == nums2.length){
while(i != nums1.length){
nums[count++] = nums1[i++];
}
break;
}
if (nums1[i] < nums2[j]) {
nums[count++] = nums1[i++];
}else{
nums[count++] = nums2[j++];
}
}
//count = nums1.length + nums2.length
if(count % 2 == 0){
return (nums[count / 2 - 1] + nums[count / 2]) / 2.0;
}else{
return nums[count / 2];
}
}
}
时间复杂度:O(m+n)
2、利用归并思想直接找到中位数,没有合并两个数组
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len = nums1.length + nums2.length;
double left = 0, right = 0;//保存这两个正序数组的中间两个数
int point1 = 0, point2 = 0;
//只需遍历len/2 + 1次
for(int i = 0; i <= len / 2; i++){
left = right;
if(point1 < nums1.length && (point2 >= nums2.length || nums1[point1] < nums2[point2])){
right = nums1[point1++];
}else{
right = nums2[point2++];
}
}
if(len % 2 == 0){
return (left + right) / 2.0;
}else{
return right;
}
}
}
时间复杂度:O((m+n)/2)
3、利用求第k小数思路
简要说明:由于数列是有序的,我们可以每次排除一半数,即假设我们要找第k小数,我们可以每次循环排除掉k/2个数,直至k=1,则下一个数为第k小数。本题中,只需寻找第中间一个数或者第中间两个数。
疑问:为什么每次减少k/2个数,当k=1时,下一个数为第k小数?(抛开第四题本身)
回答:假设在一个长度为n的正序数组中求第k小数,根据上述算法可以得知:(1)i次循环后k=1;(2)i次循环中减少的元素个数之和为k-1个,利用递推式Di = Di-1 - Di-1 / 2(向下取整),其中D1 = k,Di = 1可证
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length, len2 = nums2.length;
int len = nums1.length + nums2.length;
double median = 0.0;
if(len % 2 == 0){
int indexLeft = len / 2 - 1, indexRight = len / 2;//中间两个数的下标
median = (getKthNum(nums1,nums2,indexLeft + 1) + getKthNum(nums1,nums2,indexRight + 1)) / 2.0;
}
else{
int index = len / 2;//中间一个数的下标
median = getKthNum(nums1,nums2,index + 1);
}
return median;
}
//求第k小数
public int getKthNum(int[] nums1, int[] nums2, int k){
int len1 = nums1.length, len2 = nums2.length;
int left1 = 0, left2 = 0;//数组nums1,nums2的左边界
while(true){
//只有数组nums2有元素
if(left1 == len1)
return nums2[left2 + k - 1];
//只有数组nums2有元素
if(left2 == len2)
return nums1[left1 + k - 1];
//找到第k小数
if(k == 1)
return Math.min(nums1[left1],nums2[left2]);
//数组nums1和nums2均有元素
int mid = k / 2;
int newLeft1 = Math.min(left1 + mid,len1) - 1;//数组nums1的新左边界,其中min()保证不越界
int newLeft2 = Math.min(left2 + mid,len2) - 1;//数组nums2的新左边界,其中min()保证不越界
if(nums1[newLeft1] <= nums2[newLeft2]){
k -= (newLeft1 - left1 + 1);//根据边界之差来确定排除元素的个数
left1 = newLeft1 + 1;
}
else{
k -= (newLeft2 - left2 + 1);//根据边界之差来确定排除元素的个数
left2 = newLeft2 + 1;
}
//k -= mid;//更新k值(有问题:mid可能大于数组中的剩余元素个数)
}
}
}
时间复杂度:O(log(m+n))