题目
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数
思路
一 ,假设这个数为 n
, 如果n
是丑数,只有三种可能:
n
是能整除2
,即n % 2 == 0
,且n/2
是丑数。n % 3 == 0
且n/3
是丑数。n % 5 == 0
且n / 5
是丑数。
三种可能只要满足其中一种,就可以确认是丑数了。
二 ,为了优化内存,只能想办法不存储所有的数了,而是用一个集合存储所有的丑数,如果要求第n
个丑数,也就最多使用n
个存储空间。而判断一个数是不是丑数的方法就是判断该数在不在这个集合中。
可用unordered_set容器来存储“丑数”,先判断这个数是否在容器中,若是不在,并且该数是个“丑数”,就添加到容器中。
三,如果已知了n
个丑数,第n+1
个丑数必然是前面的某个丑数乘以2,或者乘以3,或者乘以5。至于是谁,就是都尝试一下,取最小。
现在已知6个丑数 1 2 3 4 5 6, 求第7个丑数。
可以翻译成:假设dp[i]
表示第i
个丑数的数值,已知丑数的个数为count=6
,且前6个丑数 dp[1]=1;dp[2]=2;dp[3]=3;dp[4]=4;dp[5]=5;dp[6]=6;
求dp[7]
。
则dp[7]
可能有三种情况:
- 从
i=1
开始按顺序求v = dp[i]*2
,当v>dp[6]
,可以停止,则第4
个丑数乘2
得到的8
可能是第7
个丑数。 - 从
i=1
开始按顺序求v = dp[i]*3
,当v>dp[6]
,可以停止,则第3
个丑数乘3
得到的9
可能是第7
个丑数。 - 从
i=1
开始按顺序求v = dp[i]*5
,当v>dp[6]
,可以停止,则第3
个丑数乘5
得到的10
可能是第7
个丑数。
取三种情况的最小值,得到8
,就是第7
个丑数,即dp[7] = 8
。
依此类推,可以求得第8个丑数。
有个小优化,按顺序搜索的时候并不需要每次都从1
开始,只需要从上次搜索的结束点继续搜索就行了。
例如求dp[8]
,同样有三种情况:
- 从
i=4
开始按顺序求v = dp[i]*2
,当v>dp[7]
,可以停止,则第5
个丑数乘2
得到的10
可能是第8
个丑数。 - 从
i=3
开始按顺序求v = dp[i]*3
,当v>dp[7]
,可以停止,则第3
个丑数乘3
得到的9
可能是第8
个丑数。 - 从
i=2
开始按顺序求v = dp[i]*5
,当v>dp[7]
,可以停止,则第2
个丑数乘5
得到的10
可能是第8
个丑数。
取三种情况的最小值,得到10
,即dp[8] = 9
。
#include <iostream> #include <vector> #include <cmath> using namespace std; class Solution { public: int get_ugly_num(const int index); }; int Solution::get_ugly_num(const int index) { if(index<=0) return -1; else if(index<=6) return index; vector<int> v(index,0); for(int i=1;i<=6;++i) v[i]=i; int start1=1,start2=1,start3=1; int count=6; while(count<index) { for(int i=start1;i<=count;++i) if(v[i]*2>v[count]) { start1=i; break; } for(int i=start2;i<=count;++i) if(v[i]*3>v[count]) { start2=i; break; } for(int i=start3;i<=count;++i) if(v[i]*5>v[count]) { start3=i; break; } v[++count]=min(min(v[start1]*2,v[start2]*3),v[start3]*5); } return v[count]; } int main() { int n; cin>>n; Solution s; cout<<s.get_ugly_num(n)<<endl; return 0; }
code2
class Solution { public: int GetUglyNumber_Solution(int index) { if(index<7) return index; int t2=0,t3=0,t5=0; vector<int> res(index); res[0]=1; for(int i=1;i<index;++i) { res[i]=min(res[t2]*2,min(res[t3]*3,res[t5]*5)); if(res[i]==res[t2]*2) ++t2; if(res[i]==res[t3]*3) ++t3; if(res[i]==res[t5]*5) ++t5; } return res[index-1]; } };