【leet-code清晰解题思路💯✅】4. 寻找两个正序数组的中位数

90 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

题目描述

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入: nums1 = [1,3], nums2 = [2]
输出: 2.00000
解释: 合并数组 = [1,2,3] ,中位数 2

示例 2:

输入: nums1 = [1,2], nums2 = [3,4]
输出: 2.50000
解释: 合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

提示:

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

解题思路

  • 两个有序数组查找中位数。最简单的直接将两数组合并,然后排序,输出中位数.但是排序时间复杂度为O(nlogn)。优化一下,可以用双指针去将两数组合并为一个数组,合并到中位数那个位置就可以输出了.复杂度**O(n)**解题是完全OK。的
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
   l1, l2 := len(nums1), len(nums2)
   k := (l1+l2)/2 + 1
   l1, l2 = 0, 0
   a := make([]int, 0)
   for i := 0; i < k; i++ {
      if l1 < len(nums1) {
         if l2 < len(nums2) {
            if nums1[l1] < nums2[l2] {
               a = append(a, nums1[l1])
               l1 += 1
            } else {
               a = append(a, nums2[l2])
               l2 += 1
            }
         } else {
            a = append(a, nums1[l1])
            l1 += 1
         }
      } else {
         a = append(a, nums2[l2])
         l2 += 1
      }
   }
   if (len(nums1)+len(nums2))%2 == 0 {
      return float64(a[k-1]+a[k-2]) / 2.0
   } else {
      return float64(a[k-1])
   }
}

image.png

  • 这还没上大招就99%了下面我们来讨论一下log级别的算法:
    • 写一个函数,获取两数组第k小数。直接看两数组k/2的数,数组1的k/2的数小于数组2的k/2的数,数组1k/2左边的数可以直接排除,反之同理。
    • 注意各种边界😅😅
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
   l := len(nums1) + len(nums2)
   if l%2 == 1 {
      return float64(getk(nums1, nums2, 0, 0, l/2+1))
   } else {
      a, b := float64(getk(nums1, nums2, 0, 0, l/2)), float64(getk(nums1, nums2, 0, 0, l/2+1))
      return (a + b) / 2
   }
}

func getk(nums1 []int, nums2 []int, l1, l2, k int) int {
   //控制第一个数组长度小于第二个
   if len(nums1)-l1 > len(nums2)-l2 {
      return getk(nums2, nums1, l2, l1, k)
   }
   //k=1,直接返回最小数
   if k == 1 {
      if len(nums1) == l1 {
         return nums2[l2]
      } else {
         return min(nums1[l1], nums2[l2])
      }
   }
   // 第一个数组没有,直接返回第二个数组
   if len(nums1) == l1 {
      return nums2[l2+k-1]
   }

   m1, m2 := min(len(nums1), l1+k/2), l2+k-k/2
   // 判断+递归
   if nums1[m1-1] > nums2[m2-1] {
      return getk(nums1, nums2, l1, m2, k-(m2-l2))
   } else if nums1[m1-1] < nums2[m2-1] {
      return getk(nums1, nums2, m1, l2, k-(m1-l1))
   } else {
      return nums1[m1-1]
   }

}

func min(a, b int) int {
   if a < b {
      return a
   } else {
      return b
   }
}
  • 因为数据量太小,时间没有拉开差距,但是没有占用额外空间

image.png