剑指 Offer 49. 丑数
剑指 Offer 49. 丑数
我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:
- 1 是丑数。
- n 不超过1690。
做题思路:
丑数的递推性质: 丑数只包含因子 2, 3, 5 ,因此有 “丑数 == 某较小丑数 × 某因子” (例如:10 = 5×2)。
个人理解: 将丑数数组分为以 2、3 和 5为因子的子数组, 分别以子数组为基数往后递推, 取最小的为dp[i], 此时子数组index++;
举例说明:
i = 2时,n2 = 4, n3 = 3, n5 = 5 ,dp[2] = 2
i = 3时,n2 = 4, n3 = 6, n5 = 5 ,dp[3] = 3
i = 4时,n2 = 4, n3 = 6, n5 = 5 ,dp[4] = 4
i = 5时,n2 = 6, n3 = 6, n5 = 5, dp[5] = 5
然后返回dp[5]
class Solution {
public int nthUglyNumber(int n) {
int[] dp = new int[n]; // 使用dp数组来存储丑数序列
dp[0] = 1; // dp[0]已知为1
int a = 0, b = 0, c = 0; // 下个应该通过乘2来获得新丑数的数据是第a个, 同理b, c
for(int i = 1; i < n; i++){
// 第a丑数个数需要通过乘2来得到下个丑数,第b丑数个数需要通过乘2来得到下个丑数,同理第c个数
int n2 = dp[a] * 2, n3 = dp[b] * 3, n5 = dp[c] * 5;
dp[i] = Math.min(Math.min(n2, n3), n5);
if(dp[i] == n2){
a++; // 第a个数已经通过乘2得到了一个新的丑数,那下个需要通过乘2得到一个新的丑数的数应该是第(a+1)个数
}
if(dp[i] == n3){
b++; // 第 b个数已经通过乘3得到了一个新的丑数,那下个需要通过乘3得到一个新的丑数的数应该是第(b+1)个数
}
if(dp[i] == n5){
c++; // 第 c个数已经通过乘5得到了一个新的丑数,那下个需要通过乘5得到一个新的丑数的数应该是第(c+1)个数
}
}
return dp[n-1];
}
}
如果还是不怎么懂,可以看一下这个力友一个解释吧,我觉得比较好理解一点。
可以这样理解: 有三匹马在赛跑,a马跑的最慢,b马中等,c马跑的最快 遵循一个原则,跑的慢可以先跑,但是跑的远了,就得后跑 一开始a马速度慢,所以a先跑2米, 然后b马也慢,b马跑3米, 然后a马跑的太慢了,让他先跑也只跑了两米,所以再让他先跑,所以此时 a马跑了4米,b马跑了3米,c马原地不动 此时c马以及落后太多了,所以c马得到了先跑权力。 直到我们交出了10此跑步的权力之后,结束竞争。(力友:
白痴白痴白痴)
参考链接: