算法学习记录(三)

115 阅读1分钟

归并

问:

  1. 归并排序
  2. master公式求递归函数的时间复杂度
  3. 在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。

解: 1.

function mergeOrder(arr) {
    function getRes(left, right) {
        if (left === right) {
            return arr.slice(left, right + 1)
        }
        const midIdx = Math.floor((left + right) / 2)
        const leftValue = getRes(left, midIdx)
        const rightValue = getRes(midIdx + 1, right)
        return merge(leftValue, rightValue)
    }
    function merge(leftArr, rightArr) {
        const res = []
        while (leftArr.length && rightArr.length) {
            leftArr[0] <= rightArr[0] ? res.push(leftArr.shift()) : res.push(rightArr.shift())
        }
        res.push(...leftArr, ...rightArr)
        return res
    }
    return getRes(0, arr.length - 1)
}
  1. splitArr函数中,left部分递归和right部分递归是相等的,同为数组长度的一半,满足子过程规模相当条件。适用于master公式。merge函数遍历了一次数组。表达式为T(N) = 2 * T(N/2) + O(N)。 根据master公式,时间复杂度为O(N * logN)。

  2. 这个问题可以看作,当前数的右边,有多少个数大于它,那么就意味着产生了几次当前数的小和,譬如在const arr = [1,5,6] 中,1这个数的右边有5,6两个数都大于1,那么1产生了两次小和。那么在归并解法中,当leftArr[0] < rightArr[0]时,由于arr已经是排序过后的结果了,这意味着rightArr全部都大于leftArr[0],所以leftArr[0]这个数产生了rigthArr.length次小和

    const arr = [3,1,4,2,5,10, 11]
    const left = 0
    const right = arr.length-1
    let totalNumber = 0
    function splitArr(left, right) {
        const midIdx = Math.floor((right + left) / 2)
        if (left < right) {
            const leftValue = splitArr(left, midIdx) // 0,2
            const rightValue = splitArr(midIdx + 1, right) // 3 4
            return merge(leftValue, rightValue)
        }
        return arr.slice(left, right + 1)
    }
    function merge(leftArr, rightArr) {
        const arr = []
        // 比较左右两个数组,小的数组弹出一个放入新数组
        while (leftArr.length > 0 && rightArr.length > 0) {
            if (leftArr[0] < rightArr[0]) {
                // 若右边有比左大的数,那么我们就计左边这个数会产生多少次小和,累加上去
                totalNumber += leftArr[0] * rightArr.length
                arr.push(leftArr.shift())
            } else {
                arr.push(rightArr.shift())
            }
        }
        // 剩余数组直接放到结果里面
        return arr.concat(leftArr).concat(rightArr)
    }