LeetCode 4. 寻找两个正序数组的中位数

简介: LeetCode 4. 寻找两个正序数组的中位数

 LeetCode 4. 寻找两个正序数组的中位数

 

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

算法的时间复杂度应该为 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


    思路

      • 方法1 先将两个数组有序合并至新数组中,然后根据奇偶情况返回中位数
      • 方法2 先找到中位数可能的下标值 left 和 right,然后遍历数组得到 nums[left], nums[right],再根据奇偶情况返回中位数
      • 方法3 二分法,题目要求 算法的时间复杂度应该为 O(log (m+n)) ,此方法待研究 ...


      时间复杂度

        • 方法1 O(m+n)
        • 方法2 遍历 len/2 + 1 次,len=m+n,所以时间复杂度依旧是 O(m+n)
        • 方法1 O(log (m+n))


        空间复杂度

          • 方法1 O(m+n)
          • 方法2 O(1)
          • 方法3 O(1)
          // 方法1 先将两个数组有序合并至新数组中,然后根据奇偶情况返回中位数// 空间复杂度:O(m+n)funcfindMedianSortedArrays(nums1 []int, nums2 []int) float64 {
          i, j, length1, length2 :=0, 0, len(nums1), len(nums2)
          newNums :=make([]int, 0, length1+length2)
          fori, j=0, 0; i<length1&&j<length2; {
          ifnums1[i] <nums2[j] {
          newNums=append(newNums, nums1[i])
          i++        } else {
          newNums=append(newNums, nums2[j])
          j++        }
              }
          ifi<length1 {
          newNums=append(newNums, nums1[i:]...)
              }
          ifj<length2 {
          newNums=append(newNums, nums2[j:]...)
              }
          // 1 2 3(2) 4 5if (length1+length2) %2!=0 {
          returnfloat64(newNums[(length1+length2-1)/2])
              }
          // 1 2 3(2) 4(3) 5 6returnfloat64(newNums[(length1+length2)/2] +newNums[(length1+length2)/2-1]) /float64(2)
          }
          // 方法2 先找到中位数可能的下标值left和right,然后遍历数组得到nums[left],nums[right],再根据奇偶情况返回中位数// 空间复杂度:O(1) 具体思路如下:// 1.先根据nums1和nums2的数组长度,判断 奇数/偶数 情况,得到应返回的中位数下标left,right//      奇数:left = right//      偶数:left = right - 1// 2.分别遍历nums1和nums2数组,每次找出nums1[i]和nums2[j]中的较小者。然后i,j和k(用来标记当前k是否正好是中位数的left/right下标)分别右移一位//      如果k正好是中位数的left/right下标,找到其对应值,根据奇偶情况返回不同的res值即可//      若是奇数情况,在找到了一个中位数下标后可直接返回;//      若是偶数则当 k == right,说明已经找到了两个中位数,可提前结束循环并处理res值返回funcfindMedianSortedArrays(nums1 []int, nums2 []int) float64 {
          // 先找到奇数或偶数情况下,分别对应的中位数下标l1, l2, left, right, isOdd :=len(nums1), len(nums2), 0, 0, false// 偶数:1 2(1); 3(2) 4【左1右1】 // 1; 2(1) 3(2) 4【右2】 // 1 2(1) 3(2); 4【左2】if (l1+l2)%2==0 {
          right= (l1+l2) /2left=right-1isOdd=false// 奇数:1 2 3(2); 4 5 ...    } else {
          left= (l1+l2) /2right=left// left和right一样isOdd=true    }
          i, j, k, tmp :=0, 0, 0, 0varresfloat64fori<l1||j<l2 {
          ifi<l1&&j<l2&&nums1[i] <=nums2[j] {
          tmp=nums1[i]
          i++        } elseifi<l1&&j<l2&&nums1[i] >=nums2[j] {
          tmp=nums2[j]
          j++        } elseifi<l1 {
          tmp=nums1[i]
          i++        } elseifj<l2 {
          tmp=nums2[j]
          j++        }
          ifk==left||k==right {
          res+=float64(tmp)
          ifisOdd||k==right { // 奇数直接返回结果,偶数则继续找第二个中位数break// return res            }
                  }
          k++    }
          ifisOdd {
          returnres    }
          returnres/2}
          // 上边的两种思路,时间复杂度都达不到题目的要求 O(log(m+n)。看到 log,很明显,我们只有用到二分方法才能达到。二分法待研究。。// 该方法为上述方法2优化之前的代码,较为繁琐// // func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {//  // 先找到奇数或偶数情况下,分别对应的中位数下标//  l1, l2, left, right, isOdd := len(nums1), len(nums2), 0, 0, false//  // 偶数:1 2(1); 3(2) 4【左1右1】 // 1; 2(1) 3(2) 4【右2】 // 1 2(1) 3(2); 4【左2】//  if (l1+l2)%2 == 0 {//      right = (l1 + l2) / 2//      left = right - 1//      isOdd = false//      // 奇数:1 2 3(2); 4 5 ...//  } else {//      left = (l1 + l2) / 2//      right = left // left和right一样//      isOdd = true//  }//  // fmt.Printf("%v, %v, %v \n", isOdd, left, right)//  i, j, k, tmp := 0, 0, 0, 0//  var res float64//  for i < l1 && j < l2 {//      if nums1[i] < nums2[j] {//          tmp = nums1[i]//          i++//      } else {//          tmp = nums2[j]//          j++//      }//      if k == left || k == right {//          res += float64(tmp)//          if isOdd { // 奇数直接返回结果,偶数则继续找第二个中位数//              return res//          }//      }//      k++//  }//  // fmt.Printf("i=%v, j=%v, k=%v, l1=%v, l2=%v, left=%v, right=%v\n", i, j, k, l1, l2, left, right)//  // 如果nums1或nums2其中一个数组遍历完了,且中位数还未找完,则继续遍历另一个数组//  for i < l1 {//      if k == left || k == right {//          res += float64(nums1[i])//          // 奇数直接返回结果。偶数时,k已经等于第二个中位数的下标了,说明中位数都已经找完了//          if isOdd || k == right {//              break//          }//      }//      i++//      k++//  }//  for j < l2 {//      if k == left || k == right {//          res += float64(nums2[j])//          // 奇数则找到第一个中位数后直接返回,偶数则继续找第二个中位数//          if isOdd || k == right { // 奇数 或 偶数时,k已经等于第二个中位数的下标了//              break//          }//      }//      j++//      k++//  }//  if isOdd {//      return res//  }//  return res / 2// }

          image.gif


          目录
          相关文章
          |
          9天前
          |
          C++ Python
          二刷力扣--数组
          二刷力扣--数组
          |
          14天前
          |
          存储 SQL 算法
          LeetCode第53题:最大子数组和【python 5种算法】
          LeetCode第53题:最大子数组和【python 5种算法】
          |
          10天前
          |
          索引
          【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
          【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
          |
          11天前
          |
          算法
          【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
          【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
          |
          14天前
          |
          存储 算法 数据可视化
          深入解读力扣154题:寻找旋转排序数组中的最小值 II(多种方法及详细ASCII图解)
          深入解读力扣154题:寻找旋转排序数组中的最小值 II(多种方法及详细ASCII图解)
          |
          14天前
          |
          存储 算法 数据可视化
          |
          14天前
          |
          存储 传感器 算法
          LeetCode题目89:格雷码 递归、迭代及位操作在数组合并中的应用
          LeetCode题目89:格雷码 递归、迭代及位操作在数组合并中的应用
          |
          18天前
          |
          Java
          贪心 -力扣860.柠檬水找零力扣2208.将数组和减半的最少操作次数力扣179.最大数力扣376.摆动序列
          贪心 -力扣860.柠檬水找零力扣2208.将数组和减半的最少操作次数力扣179.最大数力扣376.摆动序列
          |
          19天前
          |
          存储 算法 Java
          【经典算法】 leetcode88.合并排序的数组(Java/C/Python3实现含注释说明,Easy)
          【经典算法】 leetcode88.合并排序的数组(Java/C/Python3实现含注释说明,Easy)
          12 1
          |
          10天前
          【LeetCode刷题】前缀和解决问题:742.寻找数组的中心下标、238.除自身以外数组的乘积
          【LeetCode刷题】前缀和解决问题:742.寻找数组的中心下标、238.除自身以外数组的乘积