前端就该用 JS 刷算法33(超时了)

142 阅读1分钟

每日一题 -- 堆

719. 找出第 k 小的距离对

719. 找出第 k 小的距离对

分析

  • 使用双遍历+堆找第 k 小超时
  • 使用这种多路归并还是超时了,所以后面再看看这么弄
// 719. 找出第 k 小的距离对
// https://leetcode-cn.com/problems/find-k-th-smallest-pair-distance/

/**
 * 还是超时了
 * @分析
 * 1. 求 k 小(大),直接用堆搞他
 * 2. 这里考虑维护一个长度为 n-1 的小顶堆,然后出堆 n 次
 */
var smallestDistancePair = function (nums, k) {
    const minHeap = new Heap()
    nums = nums.sort((a, b) => a - b) // 排个序,这样最小的差值肯定在两个值之间
    for (let i = 0; i < nums.length - 1; i++) {
        minHeap.heappush(nums[i + 1] - nums[i], i, i + 1)
    }
    while (--k) {
        const [val, from, to] = minHeap.heappop()
        if (to + 1 < nums.length) {
            minHeap.heappush(nums[to + 1] - nums[from], [from, to + 1])
        }
    }
    return minHeap.data[1]
};

const Heap = function () {
    this.data = []
    // 第一个值是堆的实际长度,也就是堆末的下标
    this.data.push(0)
}


//  追加一个值
Heap.prototype.heappush = function (val, fr, to) {
    // 往尾部加一个值,然后 up 上去
    this.data.push([val, fr, to])
    this.data[0] += 1
    this.up(this.data[0])
}

//  弹出堆顶
Heap.prototype.heappop = function () {
    // 先将堆顶和堆最后一个值交换,删除,然后down 下来
    if (this.data[0] !== 1) {
        this.swap(1, this.data[0])
    }
    const res = this.data.pop()
    this.data[0] -= 1
    this.down() // 默认就是从 1 开始
    return res // 将 pop 出来的值保存一下
}

Heap.prototype.swap = function (a, b) {
    let temp = this.data[a]
    this.data[a] = this.data[b]
    this.data[b] = temp
}

// 这边第一个值就当是当前堆的长度好了 -- 默认是从根节点开始
Heap.prototype.down = function (index = 1) {
    // 已经到最后一个可以找到左右节点的第二层节点了,这样 left 和 right 就不需要再判断了
    if (index * 2 > this.data[0]) return
    const left = 2 * index
    const right = 2 * index + 1
    let target = index
    if (left <= this.data[0] && this.data[left][0] < this.data[target][0]) {
        target = left
    }
    if (right <= this.data[0] && this.data[right][0] < this.data[target][0]) {
        target = right
    }
    if (target !== index) {
        this.swap(target, index)
        // 换的是值,还得继续往下面走
        this.down(target)
    }
    // 如果没变,证明走到这里已经整理完了,下面的子树已经是ok的了
}

Heap.prototype.up = function (index) {
    if (index < 2) return
    const fatherIndex = Math.floor(index / 2)
    // 只需要和父节点比较,兄弟节点是没有比较的价值的
    if (this.data[index][0] < this.data[fatherIndex][0]) {
        this.swap(index, fatherIndex)
        this.up(fatherIndex)
    }
}