Write a program to find the n
-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5
. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12
is the sequence of the first 10
ugly numbers.
Note that 1
is typically treated as an ugly number.
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.
这题是Ugly Number 的进阶题,其中一种比较简单粗暴的做法是写一个循环,然后把每个数都扔进isUglyNumber 里判断。
后面根据提示,ugly number 肯定是由其他ugly number 相乘产生的,于是要只要根据 2,3,5 分别产生出3个ugly number 的list, 然后用merge sort 的merge 思路,把三个list 合并成一个有序的list。这个算法口述比较麻烦,最好是画一个图。
2 | 3 | 5 | min |
2 * 1 | 3 * 1 | 5 * 1 | 2 |
2 * 2 | 3 * 1 | 5 * 1 | 3 |
2 * 2 | 3 * 2 | 5 * 1 | 4 |
2 * 3 | 3 * 2 | 5 * 1 | 5 |
2 * 3 | 3 * 2 | 5 * 2 | 6 |
2 * 4 | 3 * 3 | 5* 2 | 8 |
根据这个列表来计算的话可以一直延长uglynumber 列表,每一列表示2,3,5产生的列表,每行表示一次迭代,最右边的min 列表示每次迭代产生的uglynumber。
算法就是每次都选三列中最小那个,然后更新那一列,更新的方法就是乘以当前ugly 列表里的数。比如列2,第一次乘以1,因为1是ugly list 的第一个元素,1*2 = 2,2 被选为下一ugly number, 所以要更新列2, 现在就要用2 乘以ugly list的第二个元素,即刚刚添加进去的2。
/** * @param {number} n * @return {number} */ var nthUglyNumber = function(n) { if (n <= 0) return []; var arr = [1]; var l = [1,1,1]; var c = [2,3,5]; var index = [0,0,0]; while (n > arr.length) { var min = l[0] * 2; for (var i = 0; i < 3; i++) { l[i] = arr[index[i]] *c[i]; min = Math.min(min, l[i]); } for (var i = 0; i < 3; i++) { if (l[i] == min) { index[i]++; } } arr.push(min); } return arr[arr.length-1]; };