題目描述
解題思路
中位數需要根據兩個數組長度和的奇偶決定:
- 假設
nums1.length = m,nums2.length = n
- 若
(m + n) % 2 == 0
,表示兩數組長度之和爲偶數,中位數則是中間兩個數 - 否則爲奇數,中位數是中間的數
但是我們可以不同通過分別考慮來計算最終值,只需要通過第
(m + n + 1) / 2
個數 + 第(m + n + 2) / 2
個數除以2就可以得到最終結果
1、不考慮複雜度
如果我們不考慮算法的複雜度,很容易想到,將兩個數組拼成一個大數組,然後在大數組中求中位數就OK了,此時算法的複雜度是O(m+n)
這裏只給出 Java
代碼:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
int len = n1 + n2;
int[] merge = new int[len];
int i = 0, j = 0, k = 0;
//n1 = n2
while(i < n1 && j < n2){
if(nums1[i] < nums2[j]){
merge[k] = nums1[i];
i++;
k++;
}else{
merge[k] = nums2[j];
j++;
k++;
}
}
//n1 > n2
while(i < n1){
merge[k] = nums1[i];
i++;
k++;
}
//n1 < n2
while(j < n2){
merge[k] = nums2[j];
j++;
k++;
}
double res = 0.0;
//取中位數
if(len % 2 == 0){
res = (merge[len/2 - 1] + merge[len/2]) * 1.0 / 2;
}else{
res = merge[len/2];
}
return res;
}
}
2、雙指針解法
(1)使兩個指針分別從兩個數組的開頭位置開始,比較兩個指針所指向的數的大小,誰小誰就往後移動;
(2)通過計算得到中位數的位置,得到兩指針總共需要移動的次數 k
- 若
m + n
爲偶數,應該移動(m + n) / 2 - 1
和(m + n) / 2
次 - 若
m + n
爲奇數,應該移動(m + n) / 2
次
另外需要注意的是,邊界條件的考慮,如果其中一個數組已經到最後,但是還沒有達到k次,那麼就讓另一個指針繼續往後移動
Java
代碼:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
int len = n1 + n2;
int idx1 = 0;
int idx2 = 0;
int x = 0, y = 0;
while(idx1 + idx2 < len){
if(idx1 < n1){
while(idx2 == n2 || nums1[idx1] <= nums2[idx2]){
idx1++;
if(idx1 + idx2 == (len + 1) / 2){
x = nums1[idx1 - 1];
}
if(idx1 + idx2 == (len + 2) / 2){
y = nums1[idx1 - 1];
return (x + y) * 1.0 / 2;
}
if(idx1 == n1){
break;
}
}
}
if(idx2 < n2){
while(idx1 == n1 || nums2[idx2] <= nums1[idx1]){
idx2++;
if(idx1 + idx2 == (len + 1) / 2){
x = nums2[idx2 - 1];
}
if(idx1 + idx2 == (len + 2) / 2){
y = nums2[idx2 - 1];
return (x + y) * 1.0 / 2;
}
if(idx2 == n2){
break;
}
}
}
}
return -1;
}
}
3、二分法
通過以上分析,我們可以發現,其實我們就是需要找到第(m + n + 1) / 2
個數 + 第(m + n + 2) / 2
個數即可。
但是我們需要對各種情況進行討論:
- 當一個數組比較短的時候,中位數都在另一個數組中,該如何處理
- 如何獲得 第
(m + n + 1) / 2
個數和第(m + n + 2) / 2
個數
此外,需要注意的是,當一個數組太短,導致中位數在另一個數組中時,要考慮到邊界判斷
上圖只查找了一個,另一個類似,或者以第一個爲基礎繼續查找
Java
代碼
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
int len = n1 + n2;
int md1 = (len + 1) / 2;
int md2 = (len + 2) / 2;
return (getMdVal(nums1, 0, nums2, 0, md1) + getMdVal(nums1, 0, nums2, 0, md2)) * 1.0 / 2;
}
public static int getMdVal(int[] A, int Astart, int[] B, int Bstart, int k){
if (Astart > A.length-1){
return B[Bstart + k -1];
}
if (Bstart > B.length-1){
return A[Astart + k -1];
}
if (k == 1){
return Math.min(A[Astart],B[Bstart]);
}
int Amin = 0, Bmin = 0;
if (Astart + k/2 -1 < A.length){
Amin = A[Astart + k/2 -1];
}
if (Bstart + k/2 -1 < B.length){
Bmin = B[Bstart + k/2 -1];
}
return Amin < Bmin ? getMdVal(A, Astart + k/2, B, Bstart, k-k/2):getMdVal(A, Astart, B, Bstart+k/2, k-k/2);
}
}
Python3
代碼
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
m, n = len(nums1), len(nums2)
length = m + n
md1 = (length + 1) // 2
md2 = (length + 2) // 2
def getMdVal(A, Astart, B, Bstart, k):
if Astart > (len(A) - 1):
return B[int(Bstart + k - 1)]
if Bstart > (len(B) - 1):
return A[int(Astart + k - 1)]
if k == 1:
return A[int(Astart)] if (A[int(Astart)] < B[int(Bstart)]) else B[int(Bstart)]
Amin, Bmin = 2**31-1, 2**31-1
if (Astart + k//2 - 1) < len(A):
Amin = A[int(Astart + k//2 - 1)]
if (Bstart + k//2 - 1) < len(B):
Bmin = B[int(Bstart + k//2 - 1)]
return getMdVal(A, Astart + k//2, B, Bstart, k-k//2) if Amin < Bmin else getMdVal(A, Astart, B, Bstart+k//2, k-k//2)
return (getMdVal(nums1, 0, nums2, 0, md1) + getMdVal(nums1, 0, nums2, 0, md2)) / 2
運行結果不怎麼好
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
nums = nums1 + nums2
nums.sort()
length = len(nums)
if length == 2:
return (nums[0] + nums[1])/2
if length % 2 == 0:
return (nums[length // 2 - 1] + nums[(length // 2)])/2
return nums[length // 2]
此代碼是先拼接,在查找的,貌似兩個結果差不多
C++
代碼
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
int md1 = (m + n + 1) / 2;
int md2 = (m + n + 2) / 2;
return (getMdVal(nums1, 0, nums2, 0, md1) + getMdVal(nums1, 0, nums2, 0, md2)) / 2.0;
}
int getMdVal(vector<int>& A, int Astart, vector<int>& B, int Bstart, int k) {
if (Astart >= A.size()) return B[Bstart + k - 1];
if (Bstart >= B.size()) return A[Astart + k - 1];
if (k == 1) return min(A[Astart], B[Bstart]);
int midVal1 = (Astart + k / 2 - 1 < A.size()) ? A[Astart + k / 2 - 1] : INT_MAX;
int midVal2 = (Bstart + k / 2 - 1 < B.size()) ? B[Bstart + k / 2 - 1] : INT_MAX;
if (midVal1 < midVal2) {
return getMdVal(A, Astart + k / 2, B, Bstart, k - k / 2);
} else {
return getMdVal(A, Astart, B, Bstart + k / 2, k - k / 2);
}
}
};