题目描述:咱们把只包含因子 二、3 和 5 的数称做丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。javascript
由于丑数只包含质因数 2, 3, 5,因此对于下个丑数来讲,必定是前面某个丑数乘 三、乘 4 或者乘 5 所得。java
准备三个指针 ptr二、ptr三、ptr5,它们指向的数只能乘 二、3 和 5。在循环过程当中,每次选取 2 * res[ptr2]
、3 * res[ptr3]
和 5 * res[ptr5]
这三个数中结果最小的数,而且将对应的指针向前移动。有效循环是 n 次,当循环结束后,res 数组中就按从小到大的顺序保存了丑数。git
代码以下:github
// ac地址:https://leetcode-cn.com/problems/ugly-number-ii/ // 原文地址:https://xxoo521.com/2020-03-10-ugly-number-ii/ /** * @param {number} n * @return {number} */ var nthUglyNumber = function(n) { const res = new Array(n); res[0] = 1; let ptr2 = 0, // 下个数字永远 * 2 ptr3 = 0, // 下个数字永远 * 3 ptr5 = 0; // 下个数字永远 * 5 for (let i = 1; i < n; ++i) { res[i] = Math.min(res[ptr2] * 2, res[ptr3] * 3, res[ptr5] * 5); // 说明前ptr2个丑数*2也不可能产生比i更大的丑数了 // 因此移动ptr2 if (res[i] === res[ptr2] * 2) { ++ptr2; } if (res[i] === res[ptr3] * 3) { ++ptr3; } if (res[i] === res[ptr5] * 5) { ++ptr5; } } return res[n - 1]; };
时间复杂度是\(O(N)\),空间复杂度是\(O(N)\)。算法
借助最小堆,能够在 \(O(LogN)\) 时间复杂度内找到当前最小的元素。总体算法流程是:数组
代码实现以下:this
// ac地址:https://leetcode-cn.com/problems/ugly-number-ii/ // 原文地址:https://xxoo521.com/2020-03-10-ugly-number-ii/ const defaultCmp = (x, y) => x > y; const swap = (arr, i, j) => ([arr[i], arr[j]] = [arr[j], arr[i]]); class Heap { /** * 默认是最大堆 * @param {Function} cmp */ constructor(cmp = defaultCmp) { this.container = []; this.cmp = cmp; } insert(data) { const { container, cmp } = this; container.push(data); let index = container.length - 1; while (index) { let parent = Math.floor((index - 1) / 2); if (!cmp(container[index], container[parent])) { return; } swap(container, index, parent); index = parent; } } extract() { const { container, cmp } = this; if (!container.length) { return null; } swap(container, 0, container.length - 1); const res = container.pop(); const length = container.length; let index = 0, exchange = index * 2 + 1; while (exchange < length) { // 若是有右节点,而且右节点的值大于左节点的值 let right = index * 2 + 2; if (right < length && cmp(container[right], container[exchange])) { exchange = right; } if (!cmp(container[exchange], container[index])) { break; } swap(container, exchange, index); index = exchange; exchange = index * 2 + 1; } return res; } top() { if (this.container.length) return this.container[0]; return null; } } /** * @param {number} n * @return {number} */ var nthUglyNumber = function(n) { const heap = new Heap((x, y) => x < y); const res = new Array(n); const map = {}; const primes = [2, 3, 5]; heap.insert(1); map[1] = true; for (let i = 0; i < n; ++i) { res[i] = heap.extract(); for (const prime of primes) { let tmp = res[i] * prime; if (!map[tmp]) { heap.insert(tmp); map[tmp] = true; } } } return res[n - 1]; };
时间复杂度是\(O(NlogN)\), 空间复杂度是\(O(N)\)。spa
整理不易,若对您有帮助,请给个「关注+点赞」,您的支持是我更新的动力 👇指针