题目描述
给你一个整数 n ,请你找出并返回第 n 个 丑数 。
丑数 就是只包含质因数 2、3 和/或 5 的正整数。
分析
输入: Number, 表示要找到的第 n 个整数
输出: Number, 找到的丑数
解题思路
数据结构
本体用小顶堆来完成,思路是从堆中弹出 n 个丑数。
步骤
一开始,堆中只有 1 这么一个丑数,那么在弹出的时候,不断地去生成新的丑数,然后再往里放。
丑数的生成
每个丑数,都是其它丑数 * 2 / 3 / 5 得来的,但是我们在乘的时候需要注意,如果这个数的最大因子是 3,那么它就不要和 2 进行相乘了,因为会导致重复丑数的生成,这个原因是:
例如: 3 * 2 === 2 * 3,
所以我们只要保证,每个丑数不和比他的最大因子小的数字相乘,就可以了。
过程整理
- 手写最小堆
- 把 1 放入堆
- 不断的取出最小丑数,生成新的丑数
- 返回生成的第 n 个丑数
代码
/**
* @param {number} n
* @return {number}
*/
var nthUglyNumber = function (n) {
const heap = new MinHeap((a, b) => a > b)
heap.insert(1)
let ans
while (n--) {
ans = heap.extract()
if (ans % 5 === 0) {
heap.insert(ans * 5)
} else if (ans % 3 === 0) {
heap.insert(ans * 5)
heap.insert(ans * 3)
} else {
heap.insert(ans * 5)
heap.insert(ans * 3)
heap.insert(ans * 2)
}
}
return ans
}
class MinHeap {
constructor(compareFn) {
this.heap = []
this.compareFn = compareFn
}
getLeftIndex(index) {
return index * 2 + 1
}
getRightIndex(index) {
return index * 2 + 2
}
getParentIndex(index) {
return Math.floor((index - 1) / 2)
}
size() {
return this.heap.length
}
isEmpty() {
return this.size() === 0
}
swap(parent, index) {
const arr = this.heap
;[arr[parent], arr[index]] = [arr[index], arr[parent]]
}
insert(value) {
const index = this.size()
this.heap.push(value)
this.siftUp(index)
}
siftUp(index) {
let parent = this.getParentIndex(index)
while (index > 0 && this.compareFn(this.heap[parent], this.heap[index])) {
this.swap(parent, index)
index = parent
parent = this.getParentIndex(index)
}
}
extract() {
if (this.isEmpty()) return
if (this.size() === 1) return this.heap.pop()
const removedValue = this.heap[0]
this.heap[0] = this.heap.pop()
this.siftDown(0)
return removedValue
}
siftDown(index) {
let element = index
const left = this.getLeftIndex(index)
const right = this.getRightIndex(index)
if (
index < this.size() &&
this.compareFn(this.heap[element], this.heap[left])
) {
element = left
}
if (
index < this.size() &&
this.compareFn(this.heap[element], this.heap[right])
) {
element = right
}
if (index !== element) {
this.swap(element, index)
this.siftDown(element)
}
}
top() {
return this.heap[0]
}
}