LeetCode 04 question - find the median of two positive arrays

Posted by alasxdair on Sun, 16 Jan 2022 12:34:47 +0100

LeetCode 04 question - > find the median of two positive arrays

1. Title Description

  • Find the median of two positively ordered arrays

  • Give two positively ordered (from small to large) arrays nums1 and nums2 of sizes m and N, respectively. Please find and return the median of these two positive 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: merge 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

2. Problem solving ideas

  • Idea 1: merge arrays violently, but it does not meet the time complexity requirements O(log(m+n)). The process is not analyzed in detail. See the code

    public static double findMedianSortedArraysS1(int[] nums1, int[] nums2) {
        int[] nums = new int[m+n];
        int count = 0;
        int i = 0;
        int j = 0;
        while (i < m && j < n) {
            if(nums1[i] < nums2[j]) {
                nums[count++] = nums1[i];
                i++;
            } else if (nums1[i] > nums2[j]) {
                nums[count++] = nums2[j];
                j++;
            } else {
                nums[count++] = nums1[i];
                nums[count++] = nums2[j];
                i++;
                j++;
            }
        }
        if(i <= m-1) {
            for(int k = i; k < m; k++) {
                nums[count++] = nums1[k];
            }
        }
        if(j <= n-1) {
            for(int k = j; k < n; k++) {
                nums[count++] = nums2[k];
            }
        }
        double result;
        if(nums.length % 2 == 0) {
            result = (nums[nums.length/2] + nums[nums.length/2-1]) / 2.0;
        } else {
            result = nums[nums.length / 2];
        }
        return result;
    }
    
  • Idea 2: with the help of binary search

    According to the time complexity requirement O(log(m+n)), it actually implies the need for binary search.

    • The idea is as follows:
      1. Because the two arrays are in positive order, find the median by dividing the two arrays respectively. The median must be one of the four numbers around the division line of the two arrays;

      2. Conditions to be met for split lines:

        ① Number of elements on the left = number of elements on the right (+ 1); By default, if m + n is an odd number, make one more number on the left when dividing

        ② Value of left element < = value of right element

      3. You only need to stare at an array to consider the location of the split line. Skill: stare at a shorter array to find the location of the split line, that is, as long as you find the number of left elements after nums1 segmentation, subtract it with (m + n + 1) /2 to get the number of left elements after nums2 segmentation;

      4. At this time, the left and right elements of the split line can be obtained. Here, pay attention to judge the condition ② of the split line, that is, whether the cross comparison is nums1left < = nums2right & & nums2left < = nums1right;

      5. If nums1left < = nums2right is not satisfied, the split line is too right, and the left half needs to be considered;

      6. If nums2left < = nums1right is not satisfied, it means that the division line is too left, and the right half needs to be considered;

      7. Pay attention to dealing with boundary problems.

    public static double findMedianSortedArraysS2(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length) {
            int[] temp = nums1;
            nums1 = nums2;
            nums2 = temp;
        }
        int m = nums1.length;
        int n = nums2.length;   
        //If an array is empty, it must be nums1
        if(m == 0) {
            if((m + n) % 2 == 1) {
                return nums2[n/2];
            } else {
                return (nums2[n/2] + nums2[n/2-1]) / 2.0;
            }
        }
        int left = 0;
        int right = m;
        while (left <= right) {
            int i = (left + right + 1) / 2;
            int j = (m + n + 1) / 2 - i;
            if(j != 0 && i != m && nums2[j-1] > nums1[i]) {
                left = i + 1;
            }else if(i != 0 && j !=n && nums1[i-1] > nums2[j]) {
                right = i - 1;
            } else {
                int maxLeft;
                if(i == 0) {
                    maxLeft = nums2[j-1];
                }else if(j == 0) {
                    maxLeft = nums1[i-1];
                }else {
                    maxLeft = Math.max(nums1[i-1], nums2[j-1]);
                }
                int minRight;
                if(i == m) {
                    minRight = nums2[j];
                }else if(j == n) {
                    minRight = nums1[i];
                }else {
                    minRight = Math.min(nums1[i], nums2[j]);
                }
    
                if((m+n) % 2 == 1) {
                    return maxLeft;
                } else {
                    return (maxLeft + minRight) / 2.0;
                }
            }
        }
        return 0.0;
    }
    
  • Idea 3: with the help of the idea of the K-th decimal

    Using the idea of the k-th decimal + recursive dichotomy

    • The idea is as follows:

      ① It is also the case that the total length of the array is odd and even. Note that the K decimal is found, and K is 1 more than the array index.

      a. odd number, find the (m+n)/2 + 1, that is, k = (m+n)/2 + 1;

      b. even number, find the (m+n)/2 and (m+n)/2 + 1, that is, find k twice;

      ② There are two cases: compare nums1[k/2-1] and nums2[k/2-1]

      A. nums1[k/2-1] < = nums2 [k/2-1]: note that the number smaller than nums1[k/2-1] is only the first k/2-1 number in nums1 and the first k/2-1 number in nums2 at most, that is, the number smaller than nums1[k/2-1] is only k-2 at most, so [nums1[0],nums1[k/2-1]] can be excluded;

      B. nums1 [K / 2-1] > nums2 [K / 2-1]: you can exclude [nums2[0],nums2[k/2-1]];

      ③ There are three special situations to deal with:

      a. one array is empty;

      ​ b.k==1;

      c. array out of bounds.

public static double findMedianSortedArraysS4(int[] nums1, int[] nums2) {
    int m = nums1.length;
    int n = nums2.length;
    if((m + n) % 2 == 1) {
        return findKthMinElement(nums1, nums2, (m+n)/2 + 1);
    }else {
        return (findKthMinElement(nums1,nums2,(m+n)/2) + findKthMinElement(nums1,nums2,(m+n)/2+1)) / 2.0;
    }
}

/**
 * Gets the k-th decimal in two positive arrays
 * @param nums1
 * @param nums2
 * @param k
 * @return
 */
public static int findKthMinElement(int[] nums1, int[] nums2, int k) {
    int m = nums1.length;
    int n = nums2.length;
    int i = 0;
    int j = 0;
    while (true) {
        //Special case 1: an array is empty
        if(i == m) {
            return nums2[j + k -1];
        }
        if(j == n) {
            return nums1[i + k - 1];
        }
        //Special case 2: k=1
        if(k == 1) {
            return Math.min(nums1[i], nums2[j]);
        }
        //Normal start
        int half = k/2;
        //Special case 2: Handling array out of bounds
        int newI = Math.min(i+half-1,m-1);
        int newJ = Math.min(j+half-1,n-1);
        if(nums1[newI] <= nums2[newJ]) {
            k -= newI - i + 1;
            i = newI + 1;
        } else {
            k -= newJ - j + 1;
            j = newJ + 1;
        }
    }
}

Topics: Algorithm leetcode