多陣列中位數,k大數 -- 二分思路
阿新 • • 發佈:2019-02-06
多陣列k大數
給定兩個有序陣列arr1和arr2,在給定一個整數k,返回兩個陣列的所有數中第K小的數。
例如:
arr1 = {1,2,3,4,5};
arr2 = {3,4,5};
K = 1;
因為1為所有數中最小的,所以返回1;
arr1 = {1,2,3};
arr2 = {3,4,5,6};
K = 4;
因為3為所有數中第4小的數,所以返回3;
要求:如果arr1的長度為N,arr2的長度為M,時間複雜度請達到O(log(min{M,N}))。
多陣列中位數
給定兩個有序陣列arr1和arr2,兩個陣列長度都為N,求兩個陣列中所有數的上中位數。
例如:
arr1 = {1,2,3,4};
arr2 = {3,4,5,6};
一共8個數則上中位數是第4個數,所以返回3。
arr1 = {0,1,2};
arr2 = {3,4,5};
一共6個數則上中位數是第3個數,所以返回2。
要求:時間複雜度O(logN)
尋找最小的k個數(進一步要求順序與原陣列中元素順序一致)
多陣列k大數 AC程式碼
class Solution {
public:
int findKthNum(vector<int> arr1, vector<int> arr2, int kth) {
int len1 = arr1.size();
int len2 = arr2.size();
vector <int> shortArr = len1 < len2 ? arr1 : arr2;
vector<int> longArr = len1 >= len2 ? arr1 : arr2;
int lenS = shortArr.size();
int lenL = longArr.size();
if (kth < 1 || kth > len1 + len2) // kth不符合 直接返回
return -1;
if (kth <= lenS){
return getUpMedian(shortArr, 0, kth - 1, longArr, 0, kth - 1);
}
if (kth > lenL){
if (shortArr[kth - lenL - 1] >= longArr[lenL - 1]){
return shortArr[kth - lenL - 1];
}
if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){
return longArr[kth - lenS - 1];
}
return getUpMedian(shortArr, kth - lenL, lenS - 1, longArr, kth - lenS, lenL - 1);
}
if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){
return longArr[kth - lenS - 1];
}
return getUpMedian(shortArr, 0, lenS - 1, longArr, kth - lenS, kth - 1);
}
int getUpMedian(vector<int> arr1, int l1,int r1,vector<int> arr2,int l2,int r2) {
/* int N1 = arr1.size();
int N2 = arr2.size();
int l1 = 0, r1 = N1 - 1;
int l2 = 0, r2 = N2 - 1;*/
while (l1 != r1 || l2 != r2)
{
int mid1 = (l1 + r1) / 2;
int mid2 = (l2 + r2) / 2;
// 表示 2分查詢要不要包含中間那個數 奇數是0,偶數是1
int offset = (r1 - l1 + 1) & 1 ^ 1;
if (arr1[mid1] > arr2[mid2])
{
l2 = mid2 + offset;
r1 = mid1;
}
else if (arr2[mid2] > arr1[mid1]){
l1 = mid1 + offset;
r2 = mid2;
}
else{
return arr1[mid1];
}
}// while
return arr1[l1] < arr2[l2] ? arr1[l1] : arr2[l2];
}
};
注意點:
求中位數 採用了二分思路
求中位數 用二分是 要注意長度為奇偶是不一樣的(middle位置的數要不要取的問題),還要注意最後的處理
在求第k大數時,要分情況,淘汰掉一些顯然不滿足的情況,轉換為求中位數問題,這裡需要對k的大小分類討論,見程式碼.
下面是其中一種情況的說明
Median of Two Sorted Arrays(leetcode)
ac程式碼, 藉助多陣列k大數
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int N1 = nums1.size();
int N2 = nums2.size();
int total = N1 + N2;
double ans = 0;
if (total == 0)
return ans;
if (N1 == 0)
{
if (N2 % 2 == 1)
ans = nums2[N2 / 2];
else
ans = 0.5 *(nums2[N2 / 2] + nums2[N2 / 2 - 1]);
return ans;
}
if (N2 == 0)
{
if (N1 % 2 == 1)
ans = nums1[N1 / 2];
else
ans = 0.5 *(nums1[N1 / 2] + nums1[N1 / 2 - 1]);
return ans;
}
if (total % 2 == 1) // 總共是奇數長度
{
int k = total / 2 + 1;
ans = findKthNum(nums1, nums2, k);
}
else{
int k1 = total / 2;
int k2 = k1 + 1;
ans = 0.5 * (findKthNum(nums1, nums2, k1) + findKthNum(nums1, nums2, k2));
}
return ans;
}
int findKthNum(vector<int> arr1, vector<int> arr2, int kth) {
int len1 = arr1.size();
int len2 = arr2.size();
vector<int> shortArr = len1 < len2 ? arr1 : arr2;
vector<int> longArr = len1 >= len2 ? arr1 : arr2;
int lenS = shortArr.size();
int lenL = longArr.size();
if (kth < 1 || kth > len1 + len2) // kth不符合 直接返回
return -1;
if (kth <= lenS){
return getUpMedian(shortArr, 0, kth - 1, longArr, 0, kth - 1);
}
if (kth > lenL){
if (shortArr[kth - lenL - 1] >= longArr[lenL - 1]){ // 長度小的陣列 所有元素都大於 長度大的陣列
return shortArr[kth - lenL - 1];
}
if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){ // 長度大的陣列 所有元素都大於 長度小的陣列
return longArr[kth - lenS - 1];
}
// 淘汰掉不符合的 得到中位數即可
return getUpMedian(shortArr, kth - lenL, lenS - 1, longArr, kth - lenS, lenL - 1);
}
if (longArr[kth - lenS - 1] >= shortArr[lenS - 1]){ // kth在 longArr中
return longArr[kth - lenS - 1];
}
// 淘汰掉 longArr中不符合的部分
return getUpMedian(shortArr, 0, lenS - 1, longArr, kth - lenS, kth - 1);
}
int getUpMedian(vector<int> arr1, int l1, int r1, vector<int> arr2, int l2, int r2) {
/* int N1 = arr1.size();
int N2 = arr2.size();
int l1 = 0, r1 = N1 - 1;
int l2 = 0, r2 = N2 - 1;*/
while (l1 != r1 || l2 != r2)
{
int mid1 = (l1 + r1) / 2;
int mid2 = (l2 + r2) / 2;
// 表示 2分查詢要不要包含中間那個數 奇數是0,偶數是1
int offset = (r1 - l1 + 1) & 1 ^ 1;
if (arr1[mid1] > arr2[mid2])
{
l2 = mid2 + offset;
r1 = mid1;
}
else if (arr2[mid2] > arr1[mid1]){
l1 = mid1 + offset;
r2 = mid2;
}
else{
return arr1[mid1];
}
}// while
return arr1[l1] < arr2[l2] ? arr1[l1] : arr2[l2];
}
};