不过只要工资高,自己缴纳也没啥。
关键问题是:告到底值不值,能不能拿到双倍工资?嗯,这个得看运气,毕竟这事儿不是每个公司都能顺利解决的。😜
算法题:超级丑数
题目要求是:给定一个整数 n,返回第 n 个超级丑数。超级丑数是一个只包含 2、3 和 5 作为因子的正整数。也就是说,1、2、3、4、5、6、8、9、10、12、15、16、18、20、24、25、27...这些数都可以算作超级丑数,大家看懂了吧?简单来说,超级丑数就是通过 2、3、5 这三个数字不断组合、不断乘出来的数。
看到这个问题,你的第一反应是什么?是否已经开始在心里盘算:这是个动态规划的题目吗?是不是要通过堆来高效计算每一个超级丑数?别急,先别跳进结论,我们来一层层分析。
如果你想直接用暴力解法,列出从 1 开始的每个数,然后判断这个数是否只包含 2、3 和 5 作为因子,可能会得到正确的答案,但性能上是很不理想的。因为要检查每个数的因子是不是只有 2、3 和 5,这个操作就需要 O(n) 的时间复杂度,整体时间复杂度就会变得很高,特别是当 n 很大的时候,时间消耗会非常巨大。
那么,如何高效地解决这个问题呢?其实,最优的解法是通过 动态规划 或者 最小堆 来实现。这个方法的核心思想就是:利用一个数组保存当前所有的超级丑数,并通过不断“生成”下一个超级丑数来优化计算过程。具体来说,我们可以同时维护三个指针,分别对应 2、3、5 这三个因子,每次选取最小的数生成下一个丑数。
下面来看看这段 Java 代码是怎么实现的:
public class SuperUglyNumber {
public int nthSuperUglyNumber(int n, int[] primes) {
int[] uglyNumbers = new int[n];
uglyNumbers[0] = 1;
// 初始化指针数组
int[] indices = new int[primes.length];
Arrays.fill(indices, 0);
// 初始化当前候选值数组
int[] currentValues = new int[primes.length];
for (int i = 0; i < primes.length; i++) {
currentValues[i] = primes[i];
}
for (int i = 1; i < n; i++) {
// 找出当前最小的超级丑数
int nextUgly = Arrays.stream(currentValues).min().getAsInt();
uglyNumbers[i] = nextUgly;
// 更新所有对应的指针
for (int j = 0; j < primes.length; j++) {
if (currentValues[j] == nextUgly) {
indices[j]++;
currentValues[j] = primes[j] * uglyNumbers[indices[j]];
}
}
}
return uglyNumbers[n - 1];
}
public static void main(String[] args) {
SuperUglyNumber solution = new SuperUglyNumber();
int[] primes = {2, 3, 5};
System.out.println(solution.nthSuperUglyNumber(15, primes)); // 输出第15个超级丑数
}
}
这段代码的核心思路就是利用三个指针来分别记录每个因子 2、3、5 当前能够生成的最小超级丑数,并不断更新它们。每次取当前最小的值作为下一个超级丑数,并更新对应的指针。这种方法能够避免暴力计算,提高了算法效率,避免了重复的计算。
在这个解法中,我们有三个重要的数据结构:
**uglyNumbers[]**:保存当前生成的超级丑数。 **indices[]**:记录每个因子对应的下一个候选位置。 **currentValues[]**:记录每个因子生成的当前最小值。
每次生成一个新的超级丑数后,我们都更新相应的因子位置,保证我们能够尽快得到下一个最小的超级丑数。
这个方法的时间复杂度是 O(n * k),其中 n 是我们需要找的超级丑数的个数,k 是给定的因子数量。在最坏情况下,我们需要 n 次迭代,每次都从 k 个因子中选择最小值,因此时间复杂度为 O(n * k)。
看似简单的题目,通过合理的优化,能够达到很高的效率。如果用暴力方法,不仅计算量大,还容易栽在性能的陷阱里。大家可以试着跑一跑这段代码,看看它是如何高效地计算出第 15 个超级丑数的。你会发现,通过正确的算法优化,不仅提高了性能,而且代码结构也清晰易懂。
总结一下,我觉得在做这类题目时,关键不是盲目地去验证每个数,而是要通过数学推导和动态规划的思路来减少重复计算。通过这样的方式,我们能够大幅度提高解题效率,减少不必要的性能消耗。
-END-
以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言。