丑数
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 140 ms, 内存: 14.9 MB
/*
题目思路:
使用Java Stream来实现该功能并不常见,因为它不太适合这种需要状态和顺序的操作。
不过我们仍然可以用stream生成无穷序列,然后截取第n个丑数。
我们将使用Stream.iterate和limit来实现。
*/
import java.util.stream.Stream;
import java.util.PriorityQueue;
import java.util.HashSet;
public class UglyNumberStream {
public int nthUglyNumber(int n) {
PriorityQueue<Long> heap = new PriorityQueue<>();
HashSet<Long> seen = new HashSet<>();
heap.add(1L);
seen.add(1L);
long[] primes = {2, 3, 5};
Stream<Long> stream = Stream.iterate(1L, x -> {
long currentUgly = heap.poll();
for (long prime : primes) {
long newUgly = currentUgly * prime;
if (seen.add(newUgly)) {
heap.add(newUgly);
}
}
return heap.peek();
}).limit(n);
return stream.skip(n - 1).findFirst().get().intValue();
}
}
解释
方法:
该题解采用了动态规划的方法来解决丑数问题。首先创建一个长度为 n 的数组 dp,其中 dp[i] 存储第 i+1 个丑数。初始化 dp[0] 为 1,因为 1 是第一个丑数。接着使用三个指针 a、b、c 分别指向数组中某个确定的位置,这些位置对应的元素乘以 2、3、5 后可以生成新的丑数。每次循环计算出三个可能的丑数 n2, n3, n5(分别为 dp[a]*2, dp[b]*3, dp[c]*5),取这三个数中最小的一个作为新的丑数添加到 dp 数组中。然后根据所选的丑数来更新对应的指针(如果新丑数等于 n2,则移动 a 指针;如果等于 n3,则移动 b 指针;如果等于 n5,则移动 c 指针)。这样可以保证数组 dp 按从小到大的顺序存储每一个丑数,直到填满。最后 dp[n-1] 就是第 n 个丑数。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在计算新的丑数时,要选择三个计算结果中的最小值来作为下一个丑数?
▷🦆
在更新指针a、b、c时,为什么可能会有多个指针同时移动?
▷🦆
在初始化dp数组时,为什么只设置dp[0]=1而不是预先计算更多的丑数?
▷🦆
如果在循环过程中两个或三个丑数的值相同,这种情况如何处理,会不会影响到丑数序列的正确性?
▷