Find the median and the kth smallest element in two sorted arrays

Let's first look at the prototype of this type of problem algorithm:

 Corresponding Niuke website link:

https://www.nowcoder.com/practice/08588d568e164e0a9958b5d6a3c351f5?tpId=101&&tqId=33149&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D101%26type%3D101%26page%3D2

Topic description:

Given two ordered arrays arr1 and arr2, both of which have length N, find the upper median of all numbers in the two arrays.

Upper median: Assuming that the length of the increasing sequence is n, if n is an odd number, the upper median is the n/2+1th number; otherwise, it is the nth number

[Require]

The time complexity is O(logN), and the additional space complexity is O(1)

The first line contains an integer N representing the size of the array.
The next line of N integers represents the elements in arr1 The
next line of N integers represents the elements in arr

output an integer representing the answer

enter:

4
1 2 3 4
3 4 5 6

Copy the output:

3

Copy instructions:

There are 8 numbers in total, and the upper median is the 4th smallest number, so 3 is returned.

enter:

3
0 1 2
3 4 5

Copy the output:

2

Copy instructions:

There are 6 numbers in total, then the upper median is the 3rd smallest number, so return 2

 Problem solving ideas:

 I start by finding the median of the two arrays in an array of even length. We first find the upper median in the A array as b

To find the median bit b in the B array, we compare the sizes of b and b' as follows:

1. If b==b', then the value of b is the upper median. Why? We can understand b and b' as a whole.

2. If b is greater than b'. For the upper median after the combination of A and B arrays, then it must be the fourth smallest number. At this time, we can exclude some numbers that cannot be the upper median. For example, in the A array This is because c and d are originally greater than a, b and b are greater than b' and of course greater than a', so c and d cannot be the fourth smallest number. In the same way, a' and b' in the b array can also be excluded. Then only ab in the A array and c' and d' in the B array are left in the array. We find that we can find it as long as we repeat the above. median.

3. b is less than b' and the opposite of case 2 can be proved by the same reason, you can prove it by yourself.

 When the array length is odd:

In the array with odd length, we also follow the above operation to first take out the upper median of array A and array B. There are three cases where the median in array A is c and the median in array B is c':

1.c==c'then c must be the upper median 

2. When c is greater than c', we can rule out that c, d, and e in the A array cannot be the fifth smallest number. It should be that c is greater than a, and b, a', b', and c' cannot be the sixth smallest number. , and a' and b' in array B cannot be the fifth smallest number. Here we find that there are two numbers in the A array and two numbers in the B array. The solution is to manually verify the relationship between c' and b. If it is, return it and exclude it if not. At this point, it becomes an array of equal length, and we can continue to adjust the algorithm prototype

3.c<c' and 2 are the same

Summarize:

First, find the medians of the two arrays arr1 and arr2, respectively mid1 and mid2, and compare them. If mid1 == mid2, the number is the upper median of all numbers.
       (1) When mid1 > mid2:
     if the array length N is an even number: because mid1 > mid2, mid2 cannot be the upper median of all numbers, and the numbers after mid1 in arr1 cannot be the upper median, so When the two arrays are filtered out by half, and then recursively find the upper median of all numbers for the first half of arr1 and the second half of arr2.
         If the array length N is odd: Because mid1>mid2, mid1 cannot be the upper median of all numbers, but mid2 may be. Since the two arrays of medians on the sphere
        must be equal in length, we recurse Find the upper median of all numbers for the first half of arr1 (including mid1) and the second half of arr2 (including mid2).
    (2) The situation when mid1 < mid2 is similar to 2).
 

Corresponding code:

#include<iostream>
#include<vector>
using namespace std;
int GetMidNum(vector<int>&nums1,vector<int>&nums2){
           int start1=0;
           int start2=0;
           int end1=nums1.size()-1;
           int end2=nums2.size()-1;
           int mid1=0;
           int mid2=0;
             int offset=0;
           while(start1<end1){
               mid1=(end1+start1)/2;
               mid2=(end2+start2)/2;
               offset=((end1-start1+1)&1)^1;//判断数组的长度是偶数还是奇数
               if(nums1[mid1]>nums2[mid2]){
                     end1=mid1;//变换下标
                      start2=mid2+offset;
               }
               else if(nums1[mid1]<nums2[mid2]){
                   start1=mid1+offset;
                   end2=mid2;
               }
               else{
                   return nums1[mid1];
               }
           }
           return min(nums1[start1],nums2[start2]);//返回最小的那一个
}
int main(){
    int n;
    cin>>n;
     vector<int>arr1(n);
    vector<int>arr2(n);
    for(int i=0;i<n;i++){
        cin>>arr1[i];
    }
    for(int i=0;i<n;i++){
        cin>>arr2[i];
    }
    cout<<GetMidNum(arr1,arr2);
    return 0;
}

Let's take a look at an enhanced version:

 Corresponding Niuke website link:

https://www.nowcoder.com/practice/b933e6a7924c44388fc08e807945f6c7?tpId=101&&tqId=33150&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3FtpId%3D101%26type%3D101%26page%3D1

Topic description:

Given two sorted arrays arr1 and arr2, and an integer K, return the K-th smallest number among all numbers.

[Require]

If the length of arr1 is N and the length of arr2 is M, the time complexity should reach O(\log(\min{N, M}))O(log(minN,M)), and the additional space complexity is O(1) O(1).

The first line of three integers N, M, and K respectively represent the size of the arrays arr1, arr2, and the number to be queried. The
next line of N integers represents the elements in arr1, and the
next line of M integers represents the elements in arr2.

output an integer representing the answer

enter:

5 3 1
1 2 3 4 5
3 4 5

Copy the output:

1

Copy instructions:

1 is the first smallest number of all numbers

enter:

3 4 4
1 2 3
3 4 5 6

Copy the output:

3

Copy instructions:

3 is the 4th smallest number among all numbers, so return 3

Problem solving ideas:

1. When the two arrays are of equal length, we can call the algorithm prototype of the above question.

2. When the two arrays are not of equal length, they are divided into two cases

2.1 When k is greater than the length of the longer one of the two arrays

 Assuming that we ask for the 23rd smallest number, we can first rule out that 1' to 12' are impossible. This is because they are all larger than the elements in the A array and cannot be the 23rd smallest number.

Similarly, 1 2 3 4 5 in A is also impossible. At this time, the number of possible elements in the A array is the same as the number of possible elements in B. Can we adjust the previous algorithm prototype? Assuming that we can find the upper median in these 10 numbers, which is the 5th smallest number in these ten numbers, we can calculate that the total number smaller than this upper median is 17+4=21, at this time Not 23 hours.

Here we need to compare 13' with 10, and 6 with 17 to see if they are on the median. If it is, return directly. If it is not, we only need to find the 4th smallest number among the remaining 8 numbers, and then calculate it and find that it is exactly the 23rd smallest number.

2.2 k is less than the length of the long array but less than the length of the short array

Suppose we ask for the 15th smallest number and the same as above. Now we can see those numbers in the A array are impossible. First of all, all the numbers in the A array are possible.

1' to 4' and 16' to 17' in the B array cannot be the fifteenth smallest number

 We found that the possible numbers in the B array are 5' to 15', a total of 11 numbers, and only 10 numbers in the A array are not equal in length. At this time, we manually check 5' to see if it is greater than 10. If it is greater than it is the 15th smallest If the number is not, it will be excluded, just 10 numbers are equal to the length of the A array, and the algorithm prototype can be called.

Corresponding code:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
//算法原型
  int GetMidNum(vector<int>&nums1,int start1,int end1,vector<int>&nums2,int start2,int end2){

           int mid1=0;
           int mid2=0;
             int offset=0;
           while(start1<end1){
               mid1=(end1+start1)/2;
               mid2=(end2+start2)/2;
               offset=((end1-start1+1)&1)^1;//判断长度是奇数还是偶数
               if(nums1[mid1]>nums2[mid2]){
                     end1=mid1;
                      start2=mid2+offset;
               }
               else if(nums1[mid1]<nums2[mid2]){
                   start1=mid1+offset;
                   end2=mid2;
               }
               else{
                   return nums1[mid1];
               }
           }
           return min(nums1[start1],nums2[start2]);
}

int findKthNum(vector<int>&arr1,vector<int>&arr2,int k){
    vector<int>longs=arr1.size()>=arr2.size()?arr1:arr2;//长数组
    vector<int>shorts=arr1.size()<arr2.size()?arr1:arr2;//短数组
     int shortLenth=shorts.size();
      int longLenth=longs.size();
      if(k<=shortLenth){//情况1小于短数组的长度
          return GetMidNum(shorts,0,k-1,longs,0,k-1);
      }
//情况二中的小情况1大于长数组的长度
     if(k>longLenth){
         if(shorts[k-longLenth-1]>=longs[longLenth-1]){//手动验证
             return shorts[k-longLenth-1];
         }
         if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){//手动验证
             return longs[k-shortLenth-1];
         }
//算法原型
  return GetMidNum(shorts,k-longLenth,shortLenth-1,longs,k-shortLenth,longLenth-1);
     }
//情况二中的小情况1:大于短数组的长度但是小于短数组的长度
    if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){//手动排除长数组中的一个
        return longs[k-shortLenth-1];
    }

    return GetMidNum(shorts,0,shortLenth-1,longs,k-shortLenth,longLenth-1);
}
    
int main(){
    int N,M,k;
    cin>>N>>M>>k;
    vector<int>arr1(N);
    for(int i=0;i<N;i++){
        cin>>arr1[i];
            }
    vector<int>arr2(M);
    for(int i=0;i<M;i++){
        cin>>arr2[i];
    }
    cout<<findKthNum(arr1, arr2, k);
    
    return 0;
}

 With the above foundation, we use this question to kill a few questions in seconds:

Corresponding to Niuke.com link: median of multiple groups_Niuke Tiba_Niuke.com (nowcoder.com)

Topic description:

Given two arrays arr1 and arr2 in ascending order, find the lower median of the two arrays combined

Note: The lower median refers to taking the smaller one when the numbers of the two arrays are even.

enter:

[1,2,3],[3,4,5]

return value:

3

enter:

[1,2,3],[4,5]

Copy the return value:

3

Problem-solving idea: Assume that the total length of the two arrays is len. If len is even, the lower median is the smallest number of len/2, if it is odd, it is the smallest number of len/2+1

Corresponding code:

class Solution {
public:
    int getUpMedian(vector<int>& arr1, vector<int>& arr2) {
        // write code here
          int len=(arr1.size()+arr2.size())/2;
          if(((arr1.size()+arr2.size())&1)==0){//判断奇数还是偶数长度
               len--;
          }
        return findKthNum(arr1,arr2, len+1);
    }
      int GetMidNum(vector<int>&nums1,int start1,int end1,vector<int>&nums2,int start2,int end2){

           int mid1=0;
           int mid2=0;
             int offset=0;
           while(start1<end1){
               mid1=(end1+start1)/2;
               mid2=(end2+start2)/2;
               offset=((end1-start1+1)&1)^1;
               if(nums1[mid1]>nums2[mid2]){
                     end1=mid1;
                      start2=mid2+offset;
               }
               else if(nums1[mid1]<nums2[mid2]){
                   start1=mid1+offset;
                   end2=mid2;
               }
               else{
                   return nums1[mid1];
               }
           }
           return min(nums1[start1],nums2[start2]);
}
int findKthNum(vector<int>&arr1,vector<int>&arr2,int k){
    vector<int>longs=arr1.size()>=arr2.size()?arr1:arr2;
    vector<int>shorts=arr1.size()<arr2.size()?arr1:arr2;
     int shortLenth=shorts.size();
      int longLenth=longs.size();
      if(k<=shortLenth){
          return GetMidNum(shorts,0,k-1,longs,0,k-1);
      }
     if(k>longLenth){
         if(shorts[k-longLenth-1]>=longs[longLenth-1]){
             return shorts[k-longLenth-1];
         }
         if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){
             return longs[k-shortLenth-1];
         }
  return GetMidNum(shorts,k-longLenth,shortLenth-1,longs,k-shortLenth,longLenth-1);
   }
    
    if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){
        return longs[k-shortLenth-1];
    }
    return GetMidNum(shorts,0,shortLenth-1,longs,k-shortLenth,k-1);
}
};

Let's look again:

Corresponding letecode link:

https://leetcode-cn.com/problems/median-of-two-sorted-arrays/submissions/

Topic description:

Given two positive-order (smallest to largest) arrays nums1 and nums2 of size m and n, respectively. Please find and return the median of these two positive-order arrays.

The time complexity of the algorithm should be O(log (m+n)) .

Example 1:

Input: nums1 = [1,3], nums2 = [2]
Output: 2.00000
Explanation: Merged array = [1,2,3], median 2
Example 2:

Input: nums1 = [1,2], nums2 = [3,4]
Output: 2.50000
Explanation: Merged array = [1,2,3,4], median (2 + 3) / 2 = 2.5
Example 3:

Input: nums1 = [0,0], nums2 = [0,0]
Output: 0.00000
Example 4:

Input: nums1 = [], nums2 = [1]
Output: 1.00000
Example 5:

Input: nums1 = [2], nums2 = []
Output: 2.00000

hint:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

The idea of ​​​​solving the problem is the same as the previous question: after meeting the first two questions, these two questions can be killed in seconds

Corresponding code:

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
                int len=(nums1.size()+nums2.size());
                bool even=(len&1)==0;//判断是奇数还是偶数
                if(nums1.size()!=0&&nums2.size()!=0){
                    if(even){
           return ( findKthNum(nums1,nums2,len/2)+findKthNum(nums1,nums2,len/2+1) )/2.0;//中间两个除二
                    }
                    else{//奇数
                        return findKthNum(nums1,nums2,len/2+1);
                    }
                }
                if(nums2.size()==0){

                    if(even){
                        return(double) (nums1[(len-1)/2]+nums1[len/2])/2;
                    }
                    else{
                        return nums1[len/2];
                    }
                }
                else if(nums1.size()==0){
                    if(even)
                    return(double)(nums2[(len-1)/2]+nums2[len/2])/2;
                    else{
                        return nums2[len/2];
                    }
                }
                //数组长度都为0
                else{
                    return 0;
                }
                

    }
     int GetMidNum(vector<int>&nums1,int start1,int end1,vector<int>&nums2,int start2,int end2){

           int mid1=0;
           int mid2=0;
             int offset=0;
           while(start1<end1){
               mid1=(end1+start1)/2;
               mid2=(end2+start2)/2;
               offset=((end1-start1+1)&1)^1;
               if(nums1[mid1]>nums2[mid2]){
                     end1=mid1;
                      start2=mid2+offset;
               }
               else if(nums1[mid1]<nums2[mid2]){
                   start1=mid1+offset;
                   end2=mid2;
               }
               else{
                   return nums1[mid1];
               }
           }
           return min(nums1[start1],nums2[start2]);
}
int findKthNum(vector<int>&arr1,vector<int>&arr2,int k){
    vector<int>longs=arr1.size()>=arr2.size()?arr1:arr2;
    vector<int>shorts=arr1.size()<arr2.size()?arr1:arr2;
     int shortLenth=shorts.size();
      int longLenth=longs.size();
      if(k<=shortLenth){
          return GetMidNum(shorts,0,k-1,longs,0,k-1);
      }
     if(k>longLenth){
         if(shorts[k-longLenth-1]>=longs[longLenth-1]){
             return shorts[k-longLenth-1];
         }
         if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){
             return longs[k-shortLenth-1];
         }
  return GetMidNum(shorts,k-longLenth,shortLenth-1,longs,k-shortLenth,longLenth-1);
   }
    
    if(longs[k-shortLenth-1]>=shorts[shortLenth-1]){
        return longs[k-shortLenth-1];
    }
    return GetMidNum(shorts,0,shortLenth-1,longs,k-shortLenth,k-1);
}

};

If you think it is helpful to you, please give it a thumbs up, and if there are any mistakes, please leave a message in the comment area 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324188228&siteId=291194637