开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情
给你一个整数 n ,请你找出并返回第 n 个 丑数 。
丑数 就是只包含质因数 2、3 和/或 5 的正整数。
示例 1:
输入:n = 10 输出:12 解释:[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。
示例 2:
输入:n = 1 输出:1 解释:1 通常被视为丑数。
提示:
1 <= n <= 1690
解题思路
既然是一道dp题,那么最关键的就是找到前后联系,那甚么联系呢? 显然,新的抽数一定是由之前的丑数*2 *3 5得到的 那么dp数组就应该是从1开始的抽数,当然为了让下标直接表示第几个,可以让dp[0]=0 dp[1]=1 进一步明确联系,dp[n]一定是最接近dp[n-1]的那个丑数,模板思路到此,下一步只能靠经验 这次的dp如果采用倒推,那么就向上面注释的那样,思路简单清晰,但是会超时 所以这次的新dp只能正推,直接用小丑数获取新的大丑数, 从根源上分析,人工如何计算下一个丑数?那肯定是把比较小的几个丑数分别乘2 3 5 比一下,选出最小的 那么这一步最关键, 理解每一个丑数2 *3 5都会产生新的丑数,那就分成三组看待 第一组只从左往右通过2创建新丑数, 第二组第三组同理,那只需要每次只选出最小的即可
public:
int nthUglyNumber(int n) {
// // 0为非丑 数字为第几个丑
if( n<=1 ){
return n;
}
vector<int> np(2,0);
np[1]=1;
int count=2;
for(int i=2; i<=5000000; i++){
//add a vec
np.push_back(0);
if( i%2==0 ){
np[i]=np[ i/2 ]>0? count++ :0;
}
else if( i%3==0 ){
np[i]=np[ i/3 ]>0? count++ :0;
}
else if( i%5==0 ){
np[i]=np[ i/5 ]>0? count++ :0;
}
if( count-1 == n ){
return i;
}
}
return -1;
if(n<=1){
return n;
}
vector<int> dp(2,0);
dp[1]=1;
int from2=1;
int from3=1;
int from5=1;
// 产生第i个丑数
for(int i=2 ; i<=n ; i++ ){
dp.push_back(0);// 保证不越界
int newUgly = min( dp[from2]*2 ,min( dp[from3]*3,dp[from5]*5 ) );
dp[i]=newUgly;
if( newUgly > dp[i-1] ){
dp[i]=newUgly;
}
else{
i--;
}
//把下面的else 去掉 也可以去重
if( newUgly == dp[from2]*2){
from2++;
}
else if( newUgly == dp[from3]*3 ){
from3++;
}
else if( newUgly == dp[from5]*5 ){
from5++;
}
}
return dp[n];
}
};