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


          目录
          相关文章
          |
          2月前
          |
          算法
          LeetCode第53题最大子数组和
          LeetCode第53题"最大子数组和"的解题方法,利用动态规划思想,通过一次遍历数组,维护到当前元素为止的最大子数组和,有效避免了复杂度更高的暴力解法。
          LeetCode第53题最大子数组和
          |
          2月前
          |
          存储 Java API
          LeetCode------合并两个有序数组(4)【数组】
          这篇文章介绍了LeetCode上的"合并两个有序数组"问题,并提供了三种解法:第一种是使用Java的Arrays.sort()方法直接对合并后的数组进行排序;第二种是使用辅助数组和双指针技术进行合并;第三种则是从后向前的双指针方法,避免了使用额外的辅助数组。
          LeetCode------合并两个有序数组(4)【数组】
          |
          2月前
          |
          搜索推荐 索引 Python
          【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
          本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
          82 2
          |
          2月前
          |
          Python
          【Leetcode刷题Python】53. 最大子数组和
          LeetCode第53题"最大子数组和"的Python解决方案,利用动态规划的思想,通过一次遍历数组并维护当前最大和以及全局最大和来求解。
          70 2
          |
          2月前
          |
          Python
          【Leetcode刷题Python】剑指 Offer 03. 数组中重复的数字
          解决剑指Offer题目 "数组中重复的数字" 的Python实现方法,通过使用字典来记录数组中每个数字的出现次数,快速找出重复的数字。
          31 1
          LeetCode------找到所有数组中消失的数字(6)【数组】
          这篇文章介绍了LeetCode上的"找到所有数组中消失的数字"问题,提供了一种解法,通过两次遍历来找出所有未在数组中出现的数字:第一次遍历将数组中的每个数字对应位置的值增加数组长度,第二次遍历找出所有未被增加的数字,即缺失的数字。
          |
          2月前
          |
          前端开发
          LeetCode------移动零(5)【数组】
          这篇文章介绍了LeetCode上的"移动零"问题,提出了一种使用双指针的原地操作解法,该方法首先将非零元素移动到数组前端并保持相对顺序,然后填充后续位置为零,以达到题目要求。
          |
          2月前
          |
          算法
          LeetCode第81题搜索旋转排序数组 II
          文章讲解了LeetCode第81题"搜索旋转排序数组 II"的解法,通过二分查找算法并加入去重逻辑来解决在旋转且含有重复元素的数组中搜索特定值的问题。
          LeetCode第81题搜索旋转排序数组 II
          |
          2月前
          |
          算法 索引
          LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
          这篇文章介绍了LeetCode第34题"在排序数组中查找元素的第一个和最后一个位置"的解题方法,通过使用双指针法从数组两端向中间同时查找目标值,有效地找到了目标值的首次和最后一次出现的索引位置。
          LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
          |
          2月前
          |
          算法
          LeetCode第33题搜索旋转排序数组
          这篇文章介绍了LeetCode第33题"搜索旋转排序数组"的解题方法,通过使用二分查找法并根据数组的有序性质调整搜索范围,实现了时间复杂度为O(log n)的高效搜索算法。
          LeetCode第33题搜索旋转排序数组