leetcode - 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
-10^6 <= nums1[i], nums2[i] <= 10^6

Solution

Merge Sort

Calculate the final position of the median, and merge 2 sorted list to find out the median.

Time complexity: o ( n + m ) o(n+m) o(n+m)
Space complexity: o ( 1 ) o(1) o(1)

Binary Search

If the number of merged list is even, then median is len // 2 - 1 and len // 2, if it’s odd, the median is len // 2

To find the len // 2th element, we could find how many numbers there are that are smaller than current number, and do a binary search to find the target.

Time complexity: o ( log ⁡ ( n u m s ) ∗ log ⁡ ( m + n ) ) o(\log (nums) * \log (m+n)) o(log(nums)log(m+n))
Space complexity: o ( 1 ) o(1) o(1)

Divide and conquer

Solved after help.

For the median, it’s like finding the kth element in a sorted list. The basic idea is, the left half of the array with smaller median can never contain the final median. (Because by merging another list, the median is for sure larger)

So if k is smaller than the sum of left halfs, we discard the right half of the array with larger median, otherwise we discard the left half of the array with smaller median.
Note: if the left halfs contain k numbers, we still need to discard the left half of the array with smaller median, because the final median is for sure larger than the smaller median.

Time complexity: o ( log ⁡ ( m + n ) ) o(\log (m+n)) o(log(m+n))
Space complexity: o ( 1 ) o(1) o(1)

Code

Merge Sort

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        m, n = len(nums1), len(nums2)
        final_len = m + n
        p1, p2 = 0, 0
        p = 0
        cur_num = None
        candidates = []
        while p1 < m or p2 < n:
            if p == final_len // 2 + 1:
                candidates.append(cur_num)
            if p == final_len // 2 and final_len % 2 == 0:
                candidates.append(cur_num)
            if p1 < m and p2 < n:
                if nums1[p1] <= nums2[p2]:
                    cur_num = nums1[p1]
                    p1 += 1
                else:
                    cur_num = nums2[p2]
                    p2 += 1
            elif p1 < m:
                cur_num = nums1[p1]
                p1 += 1
            elif p2 < n:
                cur_num = nums2[p2]
                p2 += 1
            p += 1
        if p == final_len // 2 + 1:
            candidates.append(cur_num)
        if p == final_len // 2 and final_len % 2 == 0:
            candidates.append(cur_num)            
        return sum(candidates) / len(candidates)

Binary Search

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        def get_smaller_number(nums: list, target: int) -> int:
            left, right = 0, len(nums) - 1
            while left < right:
                mid = (left + right + 1) >> 1
                if nums[mid] >= target:
                    right = mid - 1
                else:
                    left = mid
            mid = (left + right + 1) >> 1
            if not nums or nums[mid] >= target:
                return 0
            return mid + 1

        def find_num(nums1: list, nums2: list, k: int) -> int:
            """
            Find the num that there are k numbers that are smaller than num
            """
            # be careful of empty lists
            if not nums1:
                left, right = nums2[0], nums2[-1]
            elif not nums2:
                left, right = nums1[0], nums1[-1]
            else:
                left, right = min(nums1[0], nums2[0]), max(nums1[-1], nums2[-1])
            
            while left < right:
                mid = (left + right + 1) >> 1
                if get_smaller_number(nums1, mid) + get_smaller_number(nums2, mid) > k:
                    right = mid - 1
                else:
                    left = mid
            return (left + right + 1) >> 1


        m, n = len(nums1), len(nums2)
        final_len = m + n
        if final_len % 2 == 0:
            res1, res2 = find_num(nums1, nums2, final_len // 2), find_num(nums1, nums2, final_len // 2 - 1)
            return (res1 + res2) / 2
        else:
            res = find_num(nums1, nums2, final_len // 2)
            return res

Divide and Conquer

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        def find_kth(left1: int, right1: int, left2: int, right2: int, k: int) -> int:
            if left1 > right1:
                return nums2[left2 + k - 1]
            if left2 > right2:
                return nums1[left1 + k - 1]
            i1 = (left1 + right1) >> 1
            i2 = (left2 + right2) >> 1
            if i1 - left1 + 1 + i2 - left2 + 1 <= k:
                if nums1[i1] < nums2[i2]:
                    return find_kth(i1 + 1, right1, left2, right2, k - (i1 - left1 + 1))
                else:
                    return find_kth(left1, right1, i2 + 1, right2, k - (i2 - left2 + 1))
            else:
                if nums1[i1] > nums2[i2]:
                    return find_kth(left1, i1 - 1, left2, right2, k)
                else:
                    return find_kth(left1, right1, left2, i2 - 1, k)

        m, n = len(nums1), len(nums2)
        if (m + n) % 2 == 0:
            return (find_kth(0, m - 1, 0, n - 1, (m + n) // 2) + find_kth(0, m - 1, 0, n - 1, (m + n) // 2 + 1)) / 2
        else:
            return find_kth(0, m - 1, 0, n - 1, (m + n) // 2 + 1)

你可能感兴趣的:(OJ题目记录,leetcode,算法,职场和发展)