剑指No.49_丑数
- 题目:我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
- 最小堆方法
利用最小堆来堆丑数数组进行排序,保证其有序性。由于每个丑数都是由其前面的丑数乘上2、3、5的因子得来,就可以得到这样的一个丑数数组。并且用一个set保证数组中不会出现重复的元素。
public int nthUglyNumberWay(int n){
int[] factors = {2, 3, 5};
PriorityQueue<Long> heap = new PriorityQueue<>();
HashSet<Long> set = new HashSet<>();
set.add(1L);
heap.offer(1L);
int result = 0;
for (int i = 0; i < n; i++){
long uglyNum = heap.poll();
result = (int) uglyNum;
for (int factor : factors){
// add方法如果在set中没有添加的元素就返回true,可以用来判断是否有重复元素
if (set.add(uglyNum * factor))
heap.offer(uglyNum * factor);
}
}
return result;
}
- 动态规划
/**
* @Description:
* 三指针方法,就是要把丑数中每个元素都用2/3/5这三个因子乘一遍,
* 一个元素乘到了相应的因子就把对应因子的指针后移,意思是不要再乘它了
* 其中每次对结果取最小值是为了保证丑数数组有序
* @Author: chong
* @Data: 2021/5/27 2:42 下午
*/
public class OfficialSolution {
public int nthUglyNumberWay(int n){
int a = 0;
int b = 0;
int c = 0;
int[] dp = new int[n];
dp[0] = 1;
for (int i = 1; i < n; i++){
int n2 = dp[a] * 2;
int n3 = dp[b] * 3;
int n5 = dp[c] * 5;
dp[i] = Math.min(Math.min(n2, n3), n5);
if (dp[i] == n2) a++;
if (dp[i] == n3) b++;
if (dp[i] == n5) c++;
}
return dp[n - 1];
}
}