求两个升序序列的中位数

1.等长序列
题目来源于王道考研数据结构书

一个长度为L(L≥1)的升序序列S,处在第 ⌈L/2 ⌉ 个位置的数称为S的中位数。例如,若序列S1=(11,13, 15,17, 19), 则S1 的中位数是15,两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2= (2, 4, 6, 8, 20), 则S1和S2的中位数是11。现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。

1.1 O(n) 的解法
就是从头到尾一共数 len 个数,这个时候两个指针指向的数字较小者即为所求

int midNum ( int* a, int* b, int len ) {
	int i = 0, j = 0, k = 0;

	for ( ; k < len-1; k++ ) {
		if ( a[i] < b[j] ) {
			i++;
		}
		else {
			j++;
		}
	}

	return (a[i] < b[j])? a[i]: b[j];
}

1.2 O(logn)的解
分别求两个升序序列的 A、B 的中位数 a 和 b,
① 若 a = b, 则已找到两个序列的中位数,返回a
② 若 a < b, 则舍弃序列 A 中较小的一半, 舍弃序列 B 中较大的一半
③ 若 a > b, 则舍弃序列 A 中较大的一半, 舍弃序列 B 中较小的一半 重复过程 ① 到 ③ 直到两个序列均只含一个元素为止,返回较小者

int midNum2 ( int* a, int* b, int n ) {
	int s1 = 0, d1 = n-1, s2 = 0, d2 = n-1;
	int m1, m2;

	while ( s1 != d1 || s2 != d2 ) {
		m1 = ( s1 + d1 ) / 2;
		m2 = ( s2 + d2 ) / 2;

		if ( a[m1] == b[m2] ) {
			return a[m1];
		}
		else if ( a[m1] < b[m2] ) {

			if ( (s1 + d1) % 2 == 0 ) { // 元素个数为奇数
				s1 = m1; // 保留中间点
				d2 = m2; // 保留中间点
			}
			else { // 元素个数为偶数
				s1 = m1+1; // 不保留中间点
				d2 = m2; // 保留中间点
			}
		}
		else {
			if ( (s2 + d2) % 2 == 0 ) { // 元素个数为奇数
				s2 = m2; // 保留中间点
				d1 = m1; // 保留中间点
			}
			else { // 元素个数为偶数
				s2 = m2+1; // 不保留中间点
				d1 = m1; // 保留中间点
			}
		}

	} // end of while

	return ( a[s1] < b[s2] )? a[s1]: b[s2];
}

2.非等长序列
题目来源于 Leetcode:https://leetcode.com/problems/median-of-two-sorted-arrays/
There are two sorted arrays nums1 and nums2 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)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

看了这题的一个解法
https://leetcode.com/articles/median-of-two-sorted-arrays/

他从中位数的定义开始着手,对两个序列用i, j进行划分

left part right part
A[0], A[1], …, A[i-1] A[i], A[i+1], …, A[m-1]
B[0], B[1], …, B[j-1] B[j], B[j+1], …, B[n-1]

其中

len(left_part) = len(right_part)
max(left_part) < min(right_part)

实现的代码如下

    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        m = len(nums1)
        n = len(nums2)
        if m > n:
            return self.findMedianSortedArrays(nums2, nums1)

        imin = 0
        imax = m
        halfLen = (m + n + 1) // 2

        while imin <= imax:
            i = (imin + imax) // 2
            j = halfLen - i

            if i < m and nums2[j-1] > nums1[i]:
                # i is too small, should increase it
                imin = i + 1
            elif i > 0 and nums1[i-1] > nums2[j]:
                # i is too big, must decrease it
                imax = i - 1
            else:
                # i is perfect

                if i == 0:
                    maxOfLeft = nums2[j-1]
                elif j == 0:
                    maxOfLeft = nums1[i-1]
                else:
                    maxOfLeft = max(nums1[i-1], nums2[j-1])

                if (m + n) % 2 == 1:
                    return float(maxOfLeft)

                if i == m:
                    minOfRight = nums2[j]
                elif j == n:
                    minOfRight = nums1[i]
                else:
                    minOfRight = min(nums1[i], nums2[j])

                return (maxOfLeft + minOfRight) / 2.0

你可能感兴趣的:(数据结构和算法的学习)