题目描述:Leetcode 0004 寻找两个正序数组的中位数
分析
-
本题的考点:二分。
-
这里将nums1、nums2分别记为A、B。对于给定的数组A、B,我们要找到这两个数组中的中位数,我们考虑一个更加一般的问题,如何找到第k小的数据。
-
假设我们需要找到A[i...]和B[j...]这两个数组的第k小的数据,则我们可以比较 A [ i + ⌊ k 2 ⌋ − 1 ] A[i+lfloor frac{k}{2}rfloor-1] A[i+⌊2k⌋−1] 和 B [ j + ⌊ k 2 ⌋ − 1 ] B[j+lfloor frac{k}{2}rfloor-1] B[j+⌊2k⌋−1] 的大小,则会存在三种情况:
(1) A [ i + ⌊ k 2 ⌋ − 1 ] ≤ B [ j + ⌊ k 2 ⌋ − 1 ] A[i+lfloor frac{k}{2}rfloor-1] le B[j+lfloor frac{k}{2}rfloor-1] A[i+⌊2k⌋−1]≤B[j+⌊2k⌋−1] :说明 A [ i . . . i + ⌊ k 2 ⌋ − 1 ] A[i...i+lfloor frac{k}{2}rfloor-1] A[i...i+⌊2k⌋−1] 都不可能是第k小的数,这是因为即使 B [ j . . . j + ⌊ k 2 ⌋ − 2 ] B[j...j+lfloor frac{k}{2}rfloor-2] B[j...j+⌊2k⌋−2]都小于 A [ i + ⌊ k 2 ⌋ − 1 ] A[i+lfloor frac{k}{2}rfloor-1] A[i+⌊2k⌋−1]的话, A [ i + ⌊ k 2 ⌋ − 1 ] A[i+lfloor frac{k}{2}rfloor-1] A[i+⌊2k⌋−1]也只是第k-1小的数,因此可以被删除;
(2) A [ i + ⌊ k 2 ⌋ − 1 ] > B [ j + ⌊ k 2 ⌋ − 1 ] A[i+lfloor frac{k}{2}rfloor-1] > B[j+lfloor frac{k}{2}rfloor-1] A[i+⌊2k⌋−1]>B[j+⌊2k⌋−1] :说明 B [ j . . . j + ⌊ k 2 ⌋ − 1 ] B[j...j+lfloor frac{k}{2}rfloor-1] B[j...j+⌊2k⌋−1] 都不可能是第k小的数,同理也可以被删除;
- 下面的代码中让: n e w I = i + ⌊ k 2 ⌋ − 1 newI = i+lfloor frac{k}{2}rfloor-1 newI=i+⌊2k⌋−1, n e w J = j + ⌊ k 2 ⌋ − 1 newJ = j+lfloor frac{k}{2}rfloor-1 newJ=j+⌊2k⌋−1。
代码
- C++
class Solution { public: double findMedianSortedArrays(vector& A, vector & B) { int n = A.size() + B.size(); if (n % 2) return get(A, B, n / 2 + 1); else { int l = get(A, B, n / 2); int r = get(A, B, n / 2 + 1); return (l + r) / 2.0; } } // 在两个有序数组 A 和 B 中获取第k小(从1开始)的数据 int get(vector A, vector B, int k) { int i = 0, j = 0; // 当前考察的区间 nums1[i...], nums2[j...] while (true) { // 考虑各种边界情况 if (i == A.size()) return B[j + k - 1]; if (j == B.size()) return A[i + k - 1]; if (k == 1) return min(A[i], B[j]); int newI = min(i + k / 2, (int)A.size()) - 1; int newJ = min(j + k / 2, (int)B.size()) - 1; if (A[newI] <= B[newJ]) { k -= (newI - i + 1); // 此时应该删除A[i...newI] i = newI + 1; } else { k -= (newJ - j + 1); // 此时应该删除B[j...newJ] j = newJ + 1; } } } };
- Java
class Solution { public double findMedianSortedArrays(int[] A, int[] B) { int n = A.length + B.length; if (n % 2 != 0) { return get(A, B, n / 2 + 1); } else { int l = get(A, B, n / 2); int r = get(A, B, n / 2 + 1); return (l + r) / 2.0; } } // 在两个有序数组 A 和 B 中获取第k小(从1开始)的数据 private int get(int[] A, int[] B, int k) { int i = 0, j = 0; // 当前考察的区间 nums1[i...], nums2[j...] while (true) { // 考虑各种边界情况 if (i == A.length) return B[j + k - 1]; if (j == B.length) return A[i + k - 1]; if (k == 1) return Math.min(A[i], B[j]); int newI = Math.min(i + k / 2, A.length) - 1; int newJ = Math.min(j + k / 2, B.length) - 1; if (A[newI] <= B[newJ]) { k -= (newI - i + 1); // 此时应该删除A[i...newI] i = newI + 1; } else { k -= (newJ - j + 1); // 此时应该删除B[j...newJ] j = newJ + 1; } } } }
- Python
class Solution: def findMedianSortedArrays(self, A: List[int], B: List[int]) -> float: n = len(A) + len(B) if n % 2 == 1: return self.get(A, B, n // 2 + 1) else: l = self.get(A, B, n // 2) r = self.get(A, B, n // 2 + 1) return (l + r) / 2 def get(self, A, B, k): i = 0 j = 0 while True: if i == len(A): return B[j + k - 1] if j == len(B): return A[i + k - 1] if k == 1: return min(A[i], B[j]) newI = min(i + k // 2, len(A)) - 1 newJ = min(j + k // 2, len(B)) - 1 if A[newI] <= B[newJ]: k -= (newI - i + 1) i = newI + 1 else: k -= (newJ - j + 1) j = newJ + 1
时空复杂度分析
-
时间复杂度: O ( l o g ( n + m ) ) O(log(n+m)) O(log(n+m)),n、m为两个数组的长度。这是因为我们每次会让k减少一半。
-
空间复杂度: O ( 1 ) O(1) O(1)。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)