寻找两个正序数组的中位数

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

思路1:归并排序,时间复杂度O(m+n), 时间复杂度不满足题意

思路2:  可以简化为寻找第k小个数的问题,时间复杂度O(log(m+n)),每次把两段数组从中间分开,比较边界位置数的大小,对与小于第k小数的那些数据(假设m个)可以删除,那么问题就变成了寻找第k-m个数的问题

处理边界位置部分值得参考

func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
    len1 := len(nums1)
    len2 := len(nums2)
    left,right := (len1+len2+1)/2,(len1+len2+2)/2
    return float64(findKthElement(nums1,nums2,left)+findKthElement(nums1,nums2,right))/2

}

func findKthElement(nums1, nums2 []int, k int) int {
    if len(nums1) > len(nums2) {
        return findKthElement(nums2, nums1, k)
    }
    if len(nums1) == 0{
        return nums2[k-1]
    }
    if k == 1 {
        if nums1[0] < nums2[0] {
            return nums1[0]
        } else {
            return nums2[0]
        }
    }
    len1, len2 := len(nums1), len(nums2)
    i, j := minInt(k/2, len1)-1, minInt(k/2, len2)-1
    if nums1[i] > nums2[j]{
        return findKthElement(nums1, nums2[j+1:], k-j-1)
    }else{
        return findKthElement(nums1[i+1:], nums2, k-i-1)
    }
}

func minInt(a, b int) int {
    if a < b {
        return a
    } else {
        return b
    }
}

思路三:问题可以理解为两个排好序的数组找切割位置,找切割位置的过程可以理解为二分查找

  2 3 | 4 5
2 3 4 | 5 6 7
然后通过比较切割位置两边 数的大小找到中位数
额外需要考虑两个问题,1.奇数个数和偶数个数中位数的求法不通 2.极端位置的处理,切割位置在最左边和最右边
对短数组二分查找,m<n
时间复杂度O(log2(m+1))
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
    len1 := len(nums1)
    len2 := len(nums2)
    if len1 > len2{
        nums3 := nums1
        nums1 = nums2
        nums2 = nums3
        len1 = len(nums1)
        len2 = len(nums2)
    }
    allLength := len1 + len2
    halfLen := allLength/2
    if len1 == 1 && len2 == 1{
        return float64(float64(nums1[0])+float64(nums2[0]))/2
    }else if len1 == 1{
        if allLength % 2==0{
            numsMid := nums2[len2/2]
            numsLeft := nums2[len2/2-1]
            numsRight := nums2[len2/2+1]
            //fmt.Println(nums1[0],numsLeft,)
            if nums1[0]>numsLeft && nums1[0]<=numsMid{
                return float64(numsMid+nums1[0])/2
            }else if nums1[0]<numsRight && nums1[0]>=numsMid{
                return float64(numsMid+nums1[0])/2
            }else if nums1[0] <= numsLeft{
                return float64(numsMid+numsLeft)/2
            }else {
                return float64(numsMid+numsRight)/2
            }
        }else{
            numsLeft := nums2[len2/2-1]
            numsRight := nums2[len2/2]
            if nums1[0] <= numsLeft{
                return float64(numsLeft)
            }else if nums1[0] >= numsRight{
                return float64(numsRight)
            }else{
                return float64(nums1[0])
            }
        }
    }
    if len1 == 0{
        if len2 % 2 ==0{
            return float64(nums2[len2/2]+nums2[(len2/2)-1])/2
        }else{
            return float64(nums2[len2/2])
        }
    }
    left := 0
    right := len1

    mid := (left+right)/2

    for left <= right {
        mid = (left+right)/2
        //fmt.Println(left,right,mid,len1,halfLen)
        if mid == 0 || mid == len1{
            if mid == 0{
                if allLength % 2==0{
                    if halfLen > len1 {
                        rightNums2 := math.Min(float64(nums2[halfLen-mid]), float64(nums1[0]))
                        leftNums1 := float64(nums2[halfLen-mid-1])
                        return float64(leftNums1+rightNums2) / 2
                    }else{
                        leftNums1 := nums1[0]
                        rightNums2 := float64(nums2[halfLen-mid-1])
                        return (float64(leftNums1)+float64(rightNums2))/2
                    }
                }else{
                    leftNums2 := nums2[halfLen-mid-1]
                    rightNums2 := nums2[halfLen-mid]
                    Nums1 := nums1[mid]
                    return math.Max(math.Min(float64(Nums1), float64(rightNums2)),float64(leftNums2))
                }
            }else if mid == len1{
                if allLength % 2==0{
                    if halfLen > mid{
                        leftNums2 := math.Max(float64(nums2[halfLen-mid-1]),float64(nums1[len1-1]))
                        rightNums2 := nums2[halfLen-mid]
                        return (float64(leftNums2)+float64(rightNums2))/2
                    }else{
                        leftNums1 := nums1[len1-1]
                        rightNums2 := nums2[0]
                        return (float64(leftNums1)+float64(rightNums2))/2
                    }
                }else{
                    leftNums2 := nums2[halfLen-mid]
                    rightNums2 := nums2[halfLen-mid+1]
                    Nums1 := nums1[mid-1]
                    return math.Min(math.Max(float64(Nums1), float64(leftNums2)),float64(rightNums2))
                }
            }
        }
        leftNums2 := nums2[halfLen-mid-1]
        rightNums2 := nums2[halfLen-mid]

        leftNums1 := nums1[mid-1]
        rightNums1 := nums1[mid]
        //fmt.Println(leftNums2,rightNums2,leftNums1,rightNums1)
        if rightNums2 >= leftNums1 && rightNums1 >= leftNums2 {
            if allLength % 2==0{
                return (math.Max(float64(leftNums1), float64(leftNums2))+math.Min(float64(rightNums1), float64(rightNums2)))/2
            }else{
                return math.Max(math.Max(float64(leftNums1), float64(leftNums2)),math.Min(float64(rightNums1), float64(rightNums2)))
            }
        }else if leftNums2 > rightNums1{
            left = mid+1
        }else{
            right = mid
        }
    }
    return 0
}

posted @ 2021-09-21 01:04  LeeJuly  阅读(74)  评论(0)    收藏  举报