算法就是解题方案的准确而完整的描述,是一系列解决问题的清晰指令。一些大厂经常会考察面试者算法能力,观察面试者编码的熟练程度、思考的速度和深度,以此衡量面试者的能力和潜力,所以算法重要性不言而喻。想进大厂,就必须拿下算法,而算法学习,就是要不断地练习。为了帮助大家提升算法能力,我将带大家每天做一道算法题!
今天的题目是寻找两个正序数组的中位数(Median of Two Sorted Arrays)。
题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) {
} }
|
题解
方法一:暴力
思路及算法
先合并,再计算中位数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public double findMedianSortedArrays(int[] nums1, int[] nums2) { int i = 0, j = 0, k = 0, m = nums1.length, n = nums2.length; int[] nums = new int[m + n]; while (i < m || j < n) { if (i < m && j < n && nums1[i] < nums2[j]) { nums[k++] = nums1[i++]; } else if (i < m && j < n && nums1[i] >= nums2[j]) { nums[k++] = nums2[j++]; } else if (i < m && j >= n) { nums[k++] = nums1[i++]; } else if (i >= m) { nums[k++] = nums2[j++]; } } if ((m + n) % 2 == 0) { return (nums[(m + n) / 2] + nums[(m + n) / 2 - 1]) / 2.0; } else { return nums[(m + n) / 2]; } }
|
复杂度分析
- 时间复杂度是 O(m+n)
- 空间复杂度是 O(m+n)
方法二:二分查找
思路及算法
根据中位数的定义,当 m+n 是奇数时,中位数是两个有序数组中的第 (m+n)/2 个元素,当 m+n 是偶数时,中位数是两个有序数组中的第 (m+n)/2 个元素和第 (m+n)/2+1 个元素的平均值。因此,这道题可以转化成寻找两个有序数组中的第 k 小的数,其中 k 为 (m+n)/2 或 (m+n)/2+1。
假设两个有序数组分别是 A 和 B。要找到第 k 个元素,我们可以比较 A[k/2−1] 和 B[k/2−1],其中 / 表示整数除法。由于 A[k/2−1] 和 B[k/2−1] 的前面分别有 A[0..k/2−2] 和 B[0..k/2−2],即 k/2−1 个元素,对于 A[k/2−1] 和 B[k/2−1] 中的较小值,最多只会有 (k/2−1)+(k/2−1)≤k−2 个元素比它小,那么它就不能是第 k 小的数了。
因此我们可以归纳出三种情况:
- 如果 A[k/2−1]<B[k/2−1],则比 A[k/2−1] 小的数最多只有 A 的前 k/2−1 个数和 B 的前 k/2−1 个数,即比 A[k/2−1] 小的数最多只有 k−2 个,因此 A[k/2−1] 不可能是第 k 个数,A[0] 到 A[k/2−1] 也都不可能是第 k 个数,可以全部排除。
- 如果 A[k/2−1]>B[k/2−1],则可以排除 B[0] 到 B[k/2−1]。
- 如果 A[k/2−1]=B[k/2−1],则可以归入第一种情况处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length, n = nums2.length; int totalLength = m + n; if (totalLength % 2 == 1) { int midIndex = totalLength / 2; return getKthElement(nums1, nums2, midIndex + 1); } else { int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2; return (getKthElement(nums1, nums2, midIndex1 + 1) + getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0; } }
public int getKthElement(int[] nums1, int[] nums2, int k) {
int m = nums1.length, n = nums2.length; int index1 = 0, index2 = 0;
while (true) { if (index1 == m) { return nums2[index2 + k - 1]; } if (index2 == n) { return nums1[index1 + k - 1]; } if (k == 1) { return Math.min(nums1[index1], nums2[index2]); }
int half = k / 2; int newIndex1 = Math.min(index1 + half, m) - 1; int newIndex2 = Math.min(index2 + half, n) - 1; int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2]; if (pivot1 <= pivot2) { k -= (newIndex1 - index1 + 1); index1 = newIndex1 + 1; } else { k -= (newIndex2 - index2 + 1); index2 = newIndex2 + 1; } }
|
复杂度分析
- 时间复杂度是 O(log(m+n))
- 空间复杂度是 O(1)
好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力。