栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > JavaScript

leetCode解题记录4

JavaScript 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

leetCode解题记录4

  • 作者:陈大鱼头
  • 项目地址:ying-leetcode
  • 碎碎念:Mmmmm,不定期刷leetcode,会以JS TS PY的形式输出出来
题目描述:

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

// 则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

// 则中位数是 (2 + 3)/2 = 2.5
解题思路

这条题目本身其实不难,主要麻烦的地方是限制了时间复杂度为 O(log(m + n)),所以我们可以参考归并排序的思路去实现,那么既然是归并排序,就有两种方案,一种是自上而下的递归,另一种是 自下而上的迭代

其实就是对排好序的两个数组的扫描,判断,一直往右移,每移一次判断一次当前位置,如果两个数组总长度是奇数,事实上这个中位数就是在两个数组合并之后的最中间的值,否则则是中间位置前后的平均值,因为在这里我们不能合并数组,所以不能判断出结果。但是我们可以记录每次遍历两个数组的位置,从而不断缩小这个中位数的区间。

那么关键步骤就是:

  1. 二分两个数组得出第一个数组的left right与第二个数组的left right
  2. 进行二分的迭代或者递归
  3. 通过中位数的概念我们可以有当两个数组总长度为奇数时,则中位数是:Max(left1, left2)
  4. 当两个数组总长度为偶数时,则中位数是:(Max(left1, left2) + Max(right1, right2)) / 2
JS版

const findMedian = (start1, nums1, start2, nums2, half) => {
    const [{ length: len1 }, { length: len2 }] = [nums1, nums2]
    // 下面两个if主要是对空数组的判断,如果是有一个是空数组,则输出另一个数组的中位数
    if (start1 >= len1) {
 return nums2[start2 + half - 1]
    }
    if (start2 >= len2) {
 return nums1[start1 + half - 1]
    }
    if (half === 1) { // 此时两个数组总长度的一半就是等于1,说明两个数组就只有一个值,那么就哪个小输出哪个
 return Math.min(nums1[start1], nums2[start2])
    }
    // 下面的不变量定义主要是为了查找是否有中间值,如果没有就赋值为Infinity,否则则赋值为这个中间值
    const halfVal1 = (start1 + parseInt(half / 2) - 1 < len1
   ? nums1[start1 + parseInt(half / 2) - 1]
   : Infinity)
    const halfVal2 = (start2 + parseInt(half / 2) - 1 < len2
   ? nums2[start2 + parseInt(half / 2) - 1] 
   : Infinity)
    // 这里是二分法的核心,判断两个数组中间值的大小,如果nums1的(half / 2)比较小的话,就说明我们找的数字不在nums1的前(half / 2)数字之中,所以我们nums1就往后移动(half / 2)。反之就是nums2往后移动(half / 2)。一直用二分法递归对比没有判断过的数,从而得到结果值。
    return (halfVal1 < halfVal2
  ? findMedian(start1 + parseInt(half / 2), nums1, start2, nums2, half - parseInt(half / 2))
  : findMedian(start1, nums1, start2 + parseInt(half / 2), nums2, half - parseInt(half / 2)));
}


const findMedianSortedArrays = (nums1, nums2) => {
    const [{ length: len1 }, { length: len2 }] = [nums1, nums2]
    const totalLen = len1 + len2 // 两个数组的总长度
    return (totalLen % 2 === 1
  ? findMedian(0, nums1, 0, nums2, (totalLen + 1) / 2) // 总长度为奇数时
  : (findMedian(0, nums1, 0, nums2, totalLen / 2) + findMedian(0, nums1, 0, nums2, totalLen / 2 + 1)) / 2) // 总长度为偶数时
}


const findMedianSortedArrays2 = (nums1, nums2) => {
    let len1 = nums1.length
    let len2 = nums2.length

    // 下面交换法主要是为了统一一个方向,方便迭代
    if (len1 > len2) {
 let lenTemp = len1
 let numsTemp = nums1
 len1 = len2
 len2 = lenTemp
 nums1 = nums2
 nums2 = numsTemp
    }

    let left = 0 // 左边开始的位置
    let right = len1 // 右边开始的位置
    let mid = Math.floor((len1 + len2 + 1) / 2) // 中间位置

    // 二分法 迭代模式
    while (left <= right) {
 let i = Math.floor((left + right) / 2) // 左边遍历到的位置
 let j = Math.floor(mid - i) // 右边遍历到的位置
 if (i < len1 && nums2[j - 1] > nums1[i]) { // 如果当前左边遍历的位置还没到数组1的长度,并且数组二遍历到的元素是比数组已的元素大的,那么这该时候就说明i还太小,需要+1
     left = i + 1
 } else if (i > 0 && nums1[i - 1] > nums2[j]) { // 如上,相反的逻辑 - 1
     right = i - 1
 } else {
     let maxLeft
     let maxRight
     // 下面一层二层的判断是为了处理当有一个数组长度为0时的情况
     if (i === 0) {
  maxLeft = nums2[j - 1]
     } else if (j === 0) {
  maxLeft = nums1[i - 1]
     } else { // 此时则是获取当前遍历到的两个数组对比的最大值
  maxLeft = Math.max(nums1[i - 1], nums2[j - 1])
     }
     if ((len1 + len2) % 2 === 1) { // 如果两个数组的长度为奇数,可以直接输出最大值
  return maxLeft
     }
     // 下面则是判断数组长度加起来为偶数时的情况
     if (i === len1) { // 当i已经遍历完时,则右边中间值为第二个数组当前遍历的值
  maxRight = nums2[j]
     } else if (j === len2) { // 与上相反
  maxRight = nums1[i]
     } else { // 获取当前遍历到的值中的最大值
  maxRight = Math.min(nums1[i], nums2[j])
     }
     // 最终的值为left right两边中间值的一半
     return (maxLeft + maxRight) / 2
 }
    }
}
TS版

const findMedian = (start1: number, nums1: number[], start2: number, nums2: number[], half: number): number => {
    const [{ length: len1 }, { length: len2 }] = [nums1, nums2]
    // 下面两个if主要是对空数组的判断,如果是有一个是空数组,则输出另一个数组的中位数
    if (start1 >= len1) {
 return nums2[start2 + half - 1]
    }
    if (start2 >= len2) {
 return nums1[start1 + half - 1]
    }
    if (half === 1) { // 此时两个数组总长度的一半就是等于1,说明两个数组就只有一个值,那么就哪个小输出哪个
 return Math.min(nums1[start1], nums2[start2])
    }
    // 下面的不变量定义主要是为了查找是否有中间值,如果没有就赋值为Infinity,否则则赋值为这个中间值
    const halfVal1 = (start1 + parseInt(half / 2) - 1 < len1
   ? nums1[start1 + parseInt(half / 2) - 1]
   : Infinity)
    const halfVal2 = (start2 + parseInt(half / 2) - 1 < len2
   ? nums2[start2 + parseInt(half / 2) - 1] 
   : Infinity)
    // 这里是二分法的核心,判断两个数组中间值的大小,如果nums1的(half / 2)比较小的话,就说明我们找的数字不在nums1的前(half / 2)数字之中,所以我们nums1就往后移动(half / 2)。反之就是nums2往后移动(half / 2)。一直用二分法递归对比没有判断过的数,从而得到结果值。
    return (halfVal1 < halfVal2
  ? findMedian(start1 + parseInt(half / 2), nums1, start2, nums2, half - parseInt(half / 2))
  : findMedian(start1, nums1, start2 + parseInt(half / 2), nums2, half - parseInt(half / 2)));
}


const findMedianSortedArrays = (nums1: number, nums2: number): number => {
    const [{ length: len1 }, { length: len2 }] = [nums1, nums2]
    const totalLen = len1 + len2 // 两个数组的总长度
    return (totalLen % 2 === 1
  ? findMedian(0, nums1, 0, nums2, (totalLen + 1) / 2) // 总长度为奇数时
  : (findMedian(0, nums1, 0, nums2, totalLen / 2) + findMedian(0, nums1, 0, nums2, totalLen / 2 + 1)) / 2) // 总长度为偶数时
}


const findMedianSortedArrays2 = (nums1: number[], nums2: number[]): number => {
    let len1: number = nums1.length
    let len2: number = nums2.length

    // 下面交换法主要是为了统一一个方向,方便迭代
    if (len1 > len2) {
 let lenTemp: number = len1
 let numsTemp: number[] = nums1
 len1 = len2
 len2 = lenTemp
 nums1 = nums2
 nums2 = numsTemp
    }

    let left: number = 0 // 左边开始的位置
    let right: number = len1 // 右边开始的位置
    let mid: number = Math.floor((len1 + len2 + 1) / 2) // 中间位置

    // 二分法 迭代模式
    while (left <= right) {
 let i: number = Math.floor((left + right) / 2) // 左边遍历到的位置
 let j: number = Math.floor(mid - i) // 右边遍历到的位置
 if (i < len1 && nums2[j - 1] > nums1[i]) { // 如果当前左边遍历的位置还没到数组1的长度,并且数组二遍历到的元素是比数组已的元素大的,那么这该时候就说明i还太小,需要+1
     left = i + 1
 } else if (i > 0 && nums1[i - 1] > nums2[j]) { // 如上,相反的逻辑 - 1
     right = i - 1
 } else {
     let maxLeft: number
     let maxRight: number
     // 下面一层二层的判断是为了处理当有一个数组长度为0时的情况
     if (i === 0) {
  maxLeft = nums2[j - 1]
     } else if (j === 0) {
  maxLeft = nums1[i - 1]
     } else { // 此时则是获取当前遍历到的两个数组对比的最大值
  maxLeft = Math.max(nums1[i - 1], nums2[j - 1])
     }
     if ((len1 + len2) % 2 === 1) { // 如果两个数组的长度为奇数,可以直接输出最大值
  return maxLeft
     }
     // 下面则是判断数组长度加起来为偶数时的情况
     if (i === len1) { // 当i已经遍历完时,则右边中间值为第二个数组当前遍历的值
  maxRight = nums2[j]
     } else if (j === len2) { // 与上相反
  maxRight = nums1[i]
     } else { // 获取当前遍历到的值中的最大值
  maxRight = Math.min(nums1[i], nums2[j])
     }
     // 最终的值为left right两边中间值的一半
     return (maxLeft + maxRight) / 2
 }
    }
}
PY版
from typing import List
def findMedian(start1: int, nums1: List[int], start2: int, nums2: List[int], half: int) -> float:
    """
    :type start1: int
    :type nums1: List[int]
    :type start2: int
    :type nums2: List[int]
    :type half: int
    :rtype: float
    """
    len1 = len(nums1)
    len2 = len(nums2)

    if start1 >= len1:
 return nums2[int(start2 + half - 1)]

    if start2 >= len2:
 return nums1[int(start1 + half - 1)]

    if half == 1:
 return min(nums1[start1], nums2[start2])

    halfVal1 = float('Infinity')
    halfVal2 = float('Infinity')

    if (start1 + int(half / 2) - 1) < len1:
 halfVal1 = nums1[start1 + int(half / 2) - 1]

    if (start2 + int(half / 2) - 1) < len2:
 halfVal2 = nums2[start2 + int(half / 2) - 1]


    if halfVal1 < halfVal2:
 return findMedian(start1 + int(half / 2), nums1, start2, nums2, half - int(half / 2))
    else:
 return findMedian(start1, nums1, start2 + int(half / 2), nums2, half - int(half / 2))

def findMedianSortedArrays(nums1: List[int], nums2: List[int]) -> float:
    """
    :type nums1: List[int]
    :type nums2: List[int]
    :rtype: float
    """
    len1 = len(nums1)
    len2 = len(nums2)
    totalLen = len1 + len2
    if totalLen % 2 == 1:
 return findMedian(0, nums1, 0, nums2, (totalLen + 1) / 2)
    else:
 return (findMedian(0, nums1, 0, nums2, totalLen / 2) + findMedian(0, nums1, 0, nums2, totalLen / 2 + 1)) / 2
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号