Leetcode (4) Median of Two Sorted Arrays

Keywords: less

There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

Example 1:

nums1 = [1, 3]
nums2 = [2]
The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5

Solving problems

Time complexity: O (log (min (m + n))
Eye:
1. Sorted when two arrays
2. The time complexity of the solution is less than O(log(m+n). (The following ideas outweigh this complexity)
From the point of view of the question, look up in dichotomy.

Median
Our aim is to find such a number. A set of numbers can be divided into two subsets of equal length, so that the number of one subset is less than that of the other.

Train of thought:

  1. Define a small subset as left_part and a large subset as right_part. What we need to do is to receive two arrays nums1 and nums2, part of the smaller number to left_part, the remaining large number to right_part. It is also necessary to ensure that the two subsets are equal in length (excluding the median itself). Nums1 is divided into i and nums2 is divided into j, as follows:
nums1[0], ..., nums1[i -1] | nums1[i], ..., nums1[m]
nums2[0], ..., nums2[j -1] | nums2[j], ..., nums2[n]

Mathematical expression that satisfies the partition described above:

// 1. Number on the left = Number on the right
i + j = (m - i) + (n - j); // The case where the median is not in the array, i.e. (m + n)% 2 = 0.
i + j = (m - i) + (n - j) + 1; // The median itself exists in two arrays, i.e. (m + n)% 2!= 0.
                                // We agreed to divide the median into left_part.

// 2. All left_parts are less than or equal to right_part s, because nums1 and nums2 are sorted and do not need to be compared with their own elements.
nums2[j - 1] < nums1[i] && nums1[i - 1] < nums2[j] 
  1. After such a division is made, the median is easy to find. In the even case, the median is the mean of the maximum in left_part and the minimum in right_part. In odd cases, the median is the largest in left_part (because we agreed to assign it to left_part)
median = (max(nums1[i - 1], nums2[j - 1]) + max(nums1[i] + nums2[j])) / 2; // (m + n) % 2 = 0
median = max(nums1[i - 1], nums2[j - 1]) // (m + n) % 2 != 0    
  1. From the equation in 1, we find that for deterministic i, j is also uniquely determined. For the two cases, there are:
j = (m + n) / 2 - i;
j = (m + n + 1) / 2 - i; // (m + n) % 2 != 0 

In fact, you only need to use the second expression, because in even cases, 1/2 will not work, decimal parts in the code will be forced to reduce the whole.

  1. Therefore, this problem has turned into the dichotomy problem of finding an appropriate i in the interval [0, m]. The algorithm is described as follows:
1. Find an i = nums[mid] in the interval [left, right] (initially, left = 0, right = m) dichotomy.
Corresponding J = m + N + 1 / 2 - I.

2. Check the size relationship between left_part and right_part median:
  a. nums2[j - 1] < nums1[i] && nums1[i - 1] < nums2[j]
    i meet the requirements, stop searching, jump to 3.
  b. nums2[j - 1] > nums1[i]
    i is small, adjust the search scope to [mid, right], return 1 to execute.
  c. nums1[i - 1] > nums2[j]
    i is larger, adjust the search scope to [left, mid], return 1 to execute.
3. Calculate the median of return. The second part of the reference train of thought.
  1. These are the main ideas and steps. Next, we need to consider some special situations.
    a. Boundary problems. In other words, i = 0,j = 0, i = n, j =m may occur, making nums1[i - 1],nums2[j - 1],nums1[i],nums[j] cross the boundary. These four cases respectively indicate that nums1 and nums2 are all divided into right_part, nums1 and nums2 are all divided into left_part. Having made this clear, it will be handled very well.
    For example, when i = 0, nums1 has been partitioned into right_part, it is not necessary to judge nums1 [i-1] < nums2 [j] (the original purpose of our judgment is to ensure left_part < right_part). When calculating the median, the largest part of left_part must be nums2 [j-1], without considering nums [i-1], and the other same.
    b. left_part and right_part boundary number duplication problems. That is to say, the maximum number in left_part is the same as the minimum number in right_part, which is also a good solution. In this case, the median is the boundary repetition number, which can be divided into the stopping conditions.
    To sum up a and b, the judgment condition in step 2 of step 4 is changed to the following: uuuuuuuuuuu
(i == 0 || j == n || nums1[i - 1] <= nums2[j]) && (j == 0 || i == m || nums2[j - 1] <= nums1[i])

Source of problem solving

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size(), n = nums2.size();
        if (m > n) return findMedianSortedArrays(nums2, nums1);
        
        int left = 0, right = m;
        int i = -1, j = -1;

        // Find the right i
        while (true)
        {
            i = (left + right) / 2;
            j = (m + n + 1) / 2 - i;
            if ((i == 0 || j == n || nums1[i - 1] <= nums2[j]) &&
                (j == 0 || i == m || nums2[j - 1] <= nums1[i])) {
                break;
            }
            else if (i > 0 && nums1[i - 1] > nums2[j]) {
                right = i - 1;
            }
            else if (j > 0 && nums2[j - 1] > nums1[i]) {
                left = i + 1;
            }
        }

        // Calculate median
        int max_left = -1, min_right = -1;

        if (i == 0) max_left = nums2[j - 1];// If I = 0, the largest part of left_part must be nums2[j - 1], without considering nums1[i - 1]
        else if (j == 0) max_left = nums1[i - 1];   
        else
        {
            max_left = max(nums1[i - 1], nums2[j - 1]);
        }
        if ((m + n) % 2) {
            return max_left;// The values of i,j conform to this convention: in odd cases, the median is assigned to left_part
        }

        if (i == m) min_right = nums2[j];
        else if (j == n) min_right = nums1[i];
        else
        {
            min_right = min(nums1[i], nums2[j]);
        }
        
        return double(max_left + min_right) / 2;
    }
};

Reference resources

Discuss

Posted by Secondlaw on Thu, 27 Dec 2018 19:48:07 -0800