有序数组中找中位数
问题描述
给定两个有序数组,返回这两个数组的中位数。如果中位数有两个,则返回它们的平均值。
e.g. [1, 3, 5]和[2, 4, 6]的中位数是3.5
解决思路
如果两个数组的长度之和为奇数,则中位数有一个;否则中位数为其中两个的平均值。
从两个数组中找第k个数,可以使用递归的思路。
程序
首先,写出在有序数组a和b中找到第k大的程序:
1. 利用归并排序中的merge数组方法,时间复杂度为O(k)。
public int findKthNaive(int[] a, int[] b, int k) { int p1 = 0, p2 = 0; int i = 0; while (p1 < a.length && p2 < b.length) { if (i == k - 1) { return Math.min(a[p1], b[p2]); } if (a[p1] < b[p2]) { ++p1; } else { ++p2; } ++i; } if (p1 == a.length) { return b[k - a.length - 1]; } if (p2 == b.length) { return a[k - b.length - 1]; } return -1; }
2. 如果两个数组的长度分别为m和n,则下面方法的时间复杂度为O(log(m+n)).
public int findKthElemRec(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_mid = a_start + k / 2 - 1 < a.length ? a[a_start + k / 2 - 1] : Integer.MAX_VALUE; int b_mid = b_start + k / 2 - 1 < b.length ? b[b_start + k / 2 - 1] : Integer.MAX_VALUE; if (a_mid < b_mid) { return findKthElemRec(a, a_start + k / 2, b, b_start, k - k / 2); } else { return findKthElemRec(a, a_start, b, b_start + k / 2, k - k / 2); } }
找中位数的程序只需要调用2即可
public double findMedian(int[] a, int[] b) { int len1 = a == null ? 0 : a.length; int len2 = b == null ? 0 : b.length; int len = len1 + len2; if (len % 2 == 0) { return (findKthElemRec(a, 0, b, 0, len / 2) + findKthElemRec(a, 0, b, 0, len / 2 + 1)) / 2.0; } else { return findKthElemRec(a, 0, b, 0, len / 2 + 1); } }