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