題目:給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。
請你找出這兩個有序數組的中位數,並且要求算法的時間複雜度爲 O(log(m + n))。
你可以假設 nums1 和 nums2 不會同時爲空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
則中位數是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
則中位數是 (2 + 3)/2 = 2.5
算法思路:
- 傳統思路:用一個循環遍歷兩個數字,找到中間數字的位置,要注意區分 m+n 是奇數偶數的場景,用兩個變量分別記錄兩個數字遍歷的位置;算法比較簡單,但算法複雜度爲 O(m+n),不符合題目要求;
- 二分算法:根據題目算法複雜度的要求 O(log(m + n)),應該藉助二分算法的思路才能滿足要求,每次排除一半的數據。題目是求中位數,其實就是求第 k 小數的一種特殊情況,而求第 k 小數有一種算法。由於數列是有序的,我們可以一半兒一半兒的排除。假設我們要找第 k 小數,我們可以每次循環排除掉 k/2 個數:比較兩個數組的第 k/2 個數字,如果 k 是奇數,向下取整;如果哪個小,就表明該數組的前 k/2 個數字都不是第 k 小數字,所以可以排除;依次類推,每次排除剩餘的一半數據。注意 m+n 的和要考慮奇數和偶數,偶數時要找到中間的兩個數字並取平均值;若是奇數,只需要找到一箇中間數字即可。
算法代碼:根據算法思路2,寫出的算法具體代碼如下:
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
// 區分奇數偶數
int middleLeft = (m + n + 1) / 2;
if ((m + n) % 2 == 1) { // 奇數情況
return getMiddleData(nums1, 0, m - 1, nums2, 0, n - 1, middleLeft);;
}
// 偶數情況
int middleRight = (m + n + 2) /2;
return (getMiddleData(nums1, 0, m - 1, nums2, 0, n - 1, middleLeft)
+ getMiddleData(nums1, 0, m - 1, nums2, 0, n - 1, middleRight)) * 0.5;
}
public static int getMiddleData(int[] num1, int start1, int end1, int[] num2, int start2, int end2, int k) {
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
//讓 len1 的長度小於 len2,這樣就能保證如果有數組空了,一定是 len1
if (len1 > len2) {
return getMiddleData(num2, start2, end2, num1, start1, end1, k);
}
if (len1 <= 0) {
return num2[start2 + k - 1];
}
if (k == 1) {
return Math.min(num1[start1], num2[start2]);
}
int middleValue = k / 2; // 二分查找,每次排除一半數據
// 定位數組1的位置
int indexNum1 = len1 > middleValue ? (start1 + middleValue - 1) : end1;
// 定位數組2的位置
int indexNum2 = len2 > middleValue ? (start2 + middleValue - 1) : end2;
if (num1[indexNum1] > num2[indexNum2]) { // 排除數組2 start2到indexNum2的數據
k = k - (indexNum2 - start2 + 1); // 剩餘的待定位數據數量
return getMiddleData(num1, start1, end1, num2, indexNum2 + 1, end2, k);
} else { // 排除數組1 start1到indexNum1的數據
k = k - (indexNum1 - start1 + 1); // 剩餘的待定位數據數量
return getMiddleData(num1, indexNum1 + 1, end1, num2, start2, end2, k);
}
}
如果你有疑問或更好的算法思路,歡迎留言交流!!!