Welcome to Subscribe On Youtube

4. Median of Two Sorted Arrays

Description

Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.

The overall run time complexity should be O(log (m+n)).

 

Example 1:

Input: nums1 = [1,3], nums2 = [2]
Output: 2.00000
Explanation: merged array = [1,2,3] and median is 2.

Example 2:

Input: nums1 = [1,2], nums2 = [3,4]
Output: 2.50000
Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.

 

Constraints:

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

Solutions

Solution 1: Divide and Conquer

The problem requires the time complexity of the algorithm to be $O(\log (m + n))$, so we cannot directly traverse the two arrays, but need to use the binary search method.

If $m + n$ is odd, then the median is the $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$-th number; if $m + n$ is even, then the median is the average of the $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$-th and the $\left\lfloor\frac{m + n + 2}{2}\right\rfloor$-th numbers. In fact, we can unify it as the average of the $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$-th and the $\left\lfloor\frac{m + n + 2}{2}\right\rfloor$-th numbers.

Therefore, we can design a function $f(i, j, k)$, which represents the $k$-th smallest number in the interval $[i, m)$ of array $nums1$ and the interval $[j, n)$ of array $nums2$. The median is the average of $f(0, 0, \left\lfloor\frac{m + n + 1}{2}\right\rfloor)$ and $f(0, 0, \left\lfloor\frac{m + n + 2}{2}\right\rfloor)$.

The implementation idea of the function $f(i, j, k)$ is as follows:

  • If $i \geq m$, it means that the interval $[i, m)$ of array $nums1$ is empty, so directly return $nums2[j + k - 1]$;
  • If $j \geq n$, it means that the interval $[j, n)$ of array $nums2$ is empty, so directly return $nums1[i + k - 1]$;
  • If $k = 1$, it means to find the first number, so just return the minimum of $nums1[i]$ and $nums2[j]$;
  • Otherwise, we find the $\left\lfloor\frac{k}{2}\right\rfloor$-th number in the two arrays, denoted as $x$ and $y$. (Note, if a certain array does not have the $\left\lfloor\frac{k}{2}\right\rfloor$-th number, then we regard the $\left\lfloor\frac{k}{2}\right\rfloor$-th number as $+\infty$.) Compare the size of $x$ and $y$:
    • If $x \leq y$, it means that the $\left\lfloor\frac{k}{2}\right\rfloor$-th number of array $nums1$ cannot be the $k$-th smallest number, so we can exclude the interval $[i, i + \left\lfloor\frac{k}{2}\right\rfloor)$ of array $nums1$, and recursively call $f(i + \left\lfloor\frac{k}{2}\right\rfloor, j, k - \left\lfloor\frac{k}{2}\right\rfloor)$.
    • If $x > y$, it means that the $\left\lfloor\frac{k}{2}\right\rfloor$-th number of array $nums2$ cannot be the $k$-th smallest number, so we can exclude the interval $[j, j + \left\lfloor\frac{k}{2}\right\rfloor)$ of array $nums2$, and recursively call $f(i, j + \left\lfloor\frac{k}{2}\right\rfloor, k - \left\lfloor\frac{k}{2}\right\rfloor)$.

The time complexity is $O(\log(m + n))$, and the space complexity is $O(\log(m + n))$. Here, $m$ and $n$ are the lengths of arrays $nums1$ and $nums2$ respectively.

Why is it k/2???

For example, [1,3,5,…,99], [2,4,6,…,100] two cases

  1. A total of 100 numbers, then the 50th in all sorts. The average number from the two arrays is 25 numbers each
  2. If it is not average, then [1,2,3,…,50], [51,52,…,100] are all taken from the first array, that is, the first 25 must be From the first array

Pitfalls

  1. The k in dfs is the number of several, not the index. But start/end is index
  2. leftMedian and rightMedian are also numbers, not index int leftMedian = (m + n + 1) / 2; int rightMedian = (m + n + 2) / 2;
  3. dfs termination condition k==1
           if (k == 1) {
               return Math.min(nums1[start1], nums2[start2]);
           }
    
  • class Solution {
        private int m;
        private int n;
        private int[] nums1;
        private int[] nums2;
    
        public double findMedianSortedArrays(int[] nums1, int[] nums2) {
            m = nums1.length;
            n = nums2.length;
            this.nums1 = nums1;
            this.nums2 = nums2;
            int a = f(0, 0, (m + n + 1) / 2);
            int b = f(0, 0, (m + n + 2) / 2);
            return (a + b) / 2.0;
        }
    
        private int f(int i, int j, int k) {
            if (i >= m) {
                return nums2[j + k - 1];
            }
            if (j >= n) {
                return nums1[i + k - 1];
            }
            if (k == 1) {
                return Math.min(nums1[i], nums2[j]);
            }
            int p = k / 2;
            int x = i + p - 1 < m ? nums1[i + p - 1] : 1 << 30;
            int y = j + p - 1 < n ? nums2[j + p - 1] : 1 << 30;
            return x < y ? f(i + p, j, k - p) : f(i, j + p, k - p);
        }
    }
    
  • class Solution {
    public:
        double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
            int m = nums1.size(), n = nums2.size();
            function<int(int, int, int)> f = [&](int i, int j, int k) {
                if (i >= m) {
                    return nums2[j + k - 1];
                }
                if (j >= n) {
                    return nums1[i + k - 1];
                }
                if (k == 1) {
                    return min(nums1[i], nums2[j]);
                }
                int p = k / 2;
                int x = i + p - 1 < m ? nums1[i + p - 1] : 1 << 30;
                int y = j + p - 1 < n ? nums2[j + p - 1] : 1 << 30;
                return x < y ? f(i + p, j, k - p) : f(i, j + p, k - p);
            };
            int a = f(0, 0, (m + n + 1) / 2);
            int b = f(0, 0, (m + n + 2) / 2);
            return (a + b) / 2.0;
        }
    };
    
  • class Solution:
        def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
    
            def findKth(i: int, j: int, k: int) -> float:
                if i >= m:
                    return nums2[j + k - 1]
                if j >= n:
                    return nums1[i + k - 1]
                if k == 1:
                    return min(nums1[i], nums2[j])
    
                # Division a // b :  floordiv(a, b)
                midVal1 = nums1[i + k // 2 - 1] if i + k // 2 - 1 < m else math.inf
                midVal2 = nums2[j + k // 2 - 1] if j + k // 2 - 1 < n else math.inf
    
                if midVal1 < midVal2:
                    return findKth(i + k // 2, j, k - k // 2) # '+' or '-' k//2
                else:
                    return findKth(i, j + k // 2, k - k // 2)
    
            m = len(nums1)
            n = len(nums2)
            # Division a // b :  floordiv(a, b)
            left = (m + n + 1) // 2 
            right = (m + n + 2) // 2
            return (findKth(0, 0, left) + findKth(0, 0, right)) / 2.0
    
    ############
    
    # iteration version
    class Solution(object):
      def findMedianSortedArrays(self, nums1, nums2):
        a, b = sorted((nums1, nums2), key=len)
        m, n = len(a), len(b)
        after = (m + n - 1) / 2
        lo, hi = 0, m
        while lo < hi:
          i = (lo + hi) / 2
          if after - i - 1 < 0 or a[i] >= b[after - i - 1]:
            hi = i
          else:
            lo = i + 1
        i = lo
        nextfew = sorted(a[i:i + 2] + b[after - i:after - i + 2])
        return (nextfew[0] + nextfew[1 - (m + n) % 2]) / 2.0
    
    
  • func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
    	m, n := len(nums1), len(nums2)
    	var f func(i, j, k int) int
    	f = func(i, j, k int) int {
    		if i >= m {
    			return nums2[j+k-1]
    		}
    		if j >= n {
    			return nums1[i+k-1]
    		}
    		if k == 1 {
    			return min(nums1[i], nums2[j])
    		}
    		p := k / 2
    		x, y := 1<<30, 1<<30
    		if ni := i + p - 1; ni < m {
    			x = nums1[ni]
    		}
    		if nj := j + p - 1; nj < n {
    			y = nums2[nj]
    		}
    		if x < y {
    			return f(i+p, j, k-p)
    		}
    		return f(i, j+p, k-p)
    	}
    	a, b := f(0, 0, (m+n+1)/2), f(0, 0, (m+n+2)/2)
    	return float64(a+b) / 2.0
    }
    
  • function findMedianSortedArrays(nums1: number[], nums2: number[]): number {
        const m = nums1.length;
        const n = nums2.length;
        const f = (i: number, j: number, k: number): number => {
            if (i >= m) {
                return nums2[j + k - 1];
            }
            if (j >= n) {
                return nums1[i + k - 1];
            }
            if (k == 1) {
                return Math.min(nums1[i], nums2[j]);
            }
            const p = Math.floor(k / 2);
            const x = i + p - 1 < m ? nums1[i + p - 1] : 1 << 30;
            const y = j + p - 1 < n ? nums2[j + p - 1] : 1 << 30;
            return x < y ? f(i + p, j, k - p) : f(i, j + p, k - p);
        };
        const a = f(0, 0, Math.floor((m + n + 1) / 2));
        const b = f(0, 0, Math.floor((m + n + 2) / 2));
        return (a + b) / 2;
    }
    
    
  • /**
     * @param {number[]} nums1
     * @param {number[]} nums2
     * @return {number}
     */
    var findMedianSortedArrays = function (nums1, nums2) {
        const m = nums1.length;
        const n = nums2.length;
        const f = (i, j, k) => {
            if (i >= m) {
                return nums2[j + k - 1];
            }
            if (j >= n) {
                return nums1[i + k - 1];
            }
            if (k == 1) {
                return Math.min(nums1[i], nums2[j]);
            }
            const p = Math.floor(k / 2);
            const x = i + p - 1 < m ? nums1[i + p - 1] : 1 << 30;
            const y = j + p - 1 < n ? nums2[j + p - 1] : 1 << 30;
            return x < y ? f(i + p, j, k - p) : f(i, j + p, k - p);
        };
        const a = f(0, 0, Math.floor((m + n + 1) / 2));
        const b = f(0, 0, Math.floor((m + n + 2) / 2));
        return (a + b) / 2;
    };
    
    
  • public class Solution {
        private int m;
        private int n;
        private int[] nums1;
        private int[] nums2;
    
        public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
            m = nums1.Length;
            n = nums2.Length;
            this.nums1 = nums1;
            this.nums2 = nums2;
            int a = f(0, 0, (m + n + 1) / 2);
            int b = f(0, 0, (m + n + 2) / 2);
            return (a + b) / 2.0;
        }
    
        private int f(int i, int j, int k) {
            if (i >= m) {
                return nums2[j + k - 1];
            }
            if (j >= n) {
                return nums1[i + k - 1];
            }
            if (k == 1) {
                return Math.Min(nums1[i], nums2[j]);
            }
            int p = k / 2;
            int x = i + p - 1 < m ? nums1[i + p - 1] : 1 << 30;
            int y = j + p - 1 < n ? nums2[j + p - 1] : 1 << 30;
            return x < y ? f(i + p, j, k - p) : f(i, j + p, k - p);
        }
    }
    
  • import std/[algorithm, sequtils]
    
    proc medianOfTwoSortedArrays(nums1: seq[int], nums2: seq[int]): float =
      var
        fullList: seq[int] = concat(nums1, nums2)
        value: int = fullList.len div 2
    
      fullList.sort()
    
      if fullList.len mod 2 == 0:
        result = (fullList[value - 1] + fullList[value]) / 2
      else:
        result = fullList[value].toFloat()
    
    # Driver Code
    
    # var
    #   arrA: seq[int] = @[1, 2]
    #   arrB: seq[int] = @[3, 4, 5]
    # echo medianOfTwoSortedArrays(arrA, arrB)
    
    
    
  • class Solution {
        /**
         * @param int[] $nums1
         * @param int[] $nums2
         * @return float
         */
    
        function findMedianSortedArrays($nums1, $nums2) {
            $arr = array_merge($nums1, $nums2);
            sort($arr);
            $cnt_arr = count($arr);
    
            if ($cnt_arr % 2) {
                return $arr[$cnt_arr / 2];
            } else {
                return ($arr[intdiv($cnt_arr, 2) - 1] + $arr[intdiv($cnt_arr, 2)]) / 2;
            }
        }
    }
    
    

All Problems

All Solutions