每日一题 -- 堆
313. 超级丑数
分析
- 就是动态的从小顶堆中取最小值
- 每次都将小顶堆出来的值和 primes 相乘,去重后加入到堆中,整理
- 最后取了 n-1 次之后,就得到了第 n 个超级丑数
but:超时了
// https://leetcode-cn.com/problems/super-ugly-number/
// 313. 超级丑数
/**
* @分析 -- 超时了
*
*/
var nthSuperUglyNumber = function (n, primes) {
const len = primes.length
// 构建初始化的小顶堆
const minHeap = new Heap(len)
let map = new Map()
let count = 1
let res = 1
for (let i = 0; i < len; i++) {
map.set(primes[i], 1)
minHeap.data[i + 1] = primes[i]
minHeap.up(i)
}
while (count < n) {
res = minHeap.poll()
for (let i = 0; i < len; i++) {
const temp = primes[i] * res
if (!map.has(temp)) {
map.set(temp, 1)
minHeap.data[minHeap.data.length] = temp
for (let j = minHeap.data.length; j > 0; j--) {
minHeap.up(j)
}
}
}
count++
}
// 第 n 次循环的时候已经跳出,所以 res 取到的是 n-1 次循环的时的值,
// 但是由于第一个值是1,所以 res 就是第 n 个超级丑数
return res
};
// 构建小顶堆
const Heap = function (n) {
this.data = new Array(n + 1)
}
Heap.prototype.swap = function (a, b) {
[this.data[a], this.data[b]] = [this.data[b], this.data[a]]
}
Heap.prototype.poll = function () {
// 堆顶和最后一个值交换
this.swap(1, this.data.length - 1)
// 删除掉堆顶的值
const res = this.data.pop()
// 自上而下的整理
this.down(1)
return res
}
Heap.prototype.down = function (index) {
if (index >= this.data.length) return
const left = index * 2
const right = index * 2 + 1
let target = index
if (left < this.data.length && this.data[left] < this.data[target]) {
target = left
}
if (right < this.data.length && this.data[right] < this.data[target]) {
target = right
}
if (target !== index) {
this.swap(target, index)
// 整理子节点
this.down(target)
}
}
Heap.prototype.up = function (index) {
if (index === 1) return
const father = index >>> 1
if (this.data[index] < this.data[father]) {
this.swap(index, father)
this.up(father)
}
}