Median of Two Sorted Arrays

本文介绍了一种在O(log(m+n))的时间复杂度内找到两个有序数组中位数的方法。通过递归地排除一半的元素来逐步逼近目标元素,确保效率。

There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

只看懂了答案:

public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        int len = A.length + B.length;
        if (len % 2 == 0) {
            return (findKth(A, 0, B, 0, len / 2) + findKth(A, 0, B, 0, len / 2 + 1)) / 2.0 ;
        } else {
            return findKth(A, 0, B, 0, len / 2 + 1);
        }
    }
    
    // find kth number of two sorted array
    public static int findKth(int[] A, int A_start, int[] B, int B_start, int k){		
		if(A_start >= A.length) 
			return B[B_start + k - 1];
		if(B_start >= B.length)
			return A[A_start + k - 1];

		if (k == 1)
			return Math.min(A[A_start], B[B_start]);
		
		int A_key = A_start + k / 2 - 1 < A.length
		            ? A[A_start + k / 2 - 1]
		            : Integer.MAX_VALUE;
		int B_key = B_start + k / 2 - 1 < B.length
		            ? B[B_start + k / 2 - 1]
		            : Integer.MAX_VALUE; 
		
		if (A_key < B_key) {
			return findKth(A, A_start + k / 2, B, B_start, k - k / 2);
		} else {
			return findKth(A, A_start, B, B_start + k / 2, k - k / 2);
		}
	}
}

分析:

// 这道题的方法是每次排除 k/2 个元素,则(logk)次便可以找到要求的元素,k=m+n,即 O(log(m+n))
// 整个程序多次涉及到k/2 + 1 等操作,处理需要谨慎
// 同时注意 (k- k/2)不一定等于 k/2, 不要写错
public class Solution {
    public double findMedianSortedArrays(int A[], int B[]) {
        int len = A.length + B.length;
/**
 * 首先要确定的是元素的总数是even or odd
 * even 则求中间两个数的average value, 注意返回值是double 类型,除数是 2.0,如果是2的话,出错
 * odd 则求第 (len/2 +1)个数
 */
        if (len % 2 == 0) {
            return (findKth(A, 0, B, 0, len / 2) + findKth(A, 0, B, 0, len / 2 + 1)) / 2.0 ;
        } else {
            return findKth(A, 0, B, 0, len / 2 + 1);
        }
    }
    
    // find kth number of two sorted array
    public static int findKth(int[] A, int A_start, int[] B, int B_start, int k){
/**
 * 下面两个if是处理:
 * 一个数组长度为0,或者已经走到末尾了,则第k个元素只可能在第二个数组中,则从第二个数组中取
 * 这种情况同时说明 A.length < (A.length + B.length)/2,并且A的所有元素都在要求的median之前
 */
		if(A_start >= A.length) 
			return B[B_start + k - 1];
		if(B_start >= B.length)
			return A[A_start + k - 1];
/**
 * 由于上面的if已经check了 当A或B的length为0的情况,则下面可以保证A[A_start], B[B_start]一定是存在的
 * 所以当k等于1的时候,要查找的元素肯定是A[A_start], B[B_start]其中一个 
 */
		if (k == 1)
			return Math.min();
/**
 * 下面的操作:
 * 要找A和B的第k小元素,每次在A中取前k/2个元素,	每次在B中取前k/2个元素,则一定可以保证这两组中有一组是一定小于
 * 要查找的第k个元素。
 * eg,k=10,我们取了A中前5个,B中前5个,则肯定可以保证有一组数一定是在 merge(A,B)的第10个数之前的
 * 那么用来判断这5(即)个数是属于A的还是B的,则用 A_key和B_key来进行比较
 * eg a: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19
 * 	  b: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20
 * 此时 A_key = 9, B_key = 10.那么a的前5个数 肯定属于merge(a,b)的前10个数之前,
 * 所以下次查找,对于a数组,就可以从a的第六个元素开始找,这时候要找的是 剩下数的 第 10-(10/2)个元素即可
 *  
 *   
 * 当A_key 或者 B_key 为MAX_VALUE 的情况:
 * a(3个元素):  1,2,100	
 * b(17个元素):3,4,5,6,7,8,9,20,21,22,23,,,,,,
 * 则median是merge(a,b)的第10个元素
 * 此时,对a取5个,对b取5个。但是a一共只有三个元素,则一共只取了8个元素,
 * 那么此时,肯定可以保证的是 b取的前5个元素肯定是在前10个中的(因为假设取的这8个都是最小的了,
 * 那么还需要往后再找两个,肯定也是在b[4](b的第5个原色)的后面。所以 b[0]-b[4]是肯定小于media 的)
 */
		int A_key = A_start + k / 2 - 1 < A.length
		            ? A[A_start + k / 2 - 1]
		            : Integer.MAX_VALUE;
		int B_key = B_start + k / 2 - 1 < B.length
		            ? B[B_start + k / 2 - 1]
		            : Integer.MAX_VALUE; 
		
		if (A_key < B_key) {
			return findKth(A, A_start + k / 2, B, B_start, k - k / 2);
		} else {
			return findKth(A, A_start, B, B_start + k / 2, k - k / 2);
		}
	}
}




题目描述是关于寻找两个已排序数组 `nums1` 和 `nums2` 的合并后的中位数。这两个数组分别包含 `m` 和 `n` 个元素。要解决这个问题,首先我们需要合并这两个数组并保持有序,然后根据数组的总大小决定取中间值的方式。 1. 合并两个数组:由于数组是有序的,我们可以使用双指针法,一个指向 `nums1` 的起始位置,另一个指向 `nums2` 的起始位置。比较两个指针所指元素的大小,将较小的那个放入一个新的合并数组中,同时移动对应指针。直到其中一个数组遍历完毕,再将另一个数组剩余的部分直接复制到合并数组中。 2. 计算中位数:如果合并数组的长度为奇数,则中位数就是最中间的那个元素;如果长度为偶数,则中位数是中间两个元素的平均值。我们可以通过检查数组长度的奇偶性来确定这一点。 下面是Python的一个基本解决方案: ```python def findMedianSortedArrays(nums1, nums2): merged = [] i, j = 0, 0 # Merge both arrays while i < len(nums1) and j < len(nums2): if nums1[i] < nums2[j]: merged.append(nums1[i]) i += 1 else: merged.append(nums2[j]) j += 1 # Append remaining elements from longer array while i < len(nums1): merged.append(nums1[i]) i += 1 while j < len(nums2): merged.append(nums2[j]) j += 1 # Calculate median length = len(merged) mid = length // 2 if length % 2 == 0: # If even, return average of middle two elements return (merged[mid - 1] + merged[mid]) / 2.0 else: # If odd, return middle element return merged[mid] ``` 这个函数返回的是两个数组合并后的中位数。注意,这里假设数组 `nums1` 和 `nums2` 都是非空的,并且已经按照升序排列。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值