剑指 Offer 49. 丑数 - 力扣(LeetCode)
剑指 Offer 49. 丑数 - 力扣(LeetCode)
题目描述
找出第n个质因数只有2,3,5的数,n<2000
解题思路
方法一:动态规划
考虑第n个数,它必定是由前n-1个数中的某个数乘以2或3或5得到的。假设第一个乘以2大于第n-1个数的数为a,同理可得到b和c,则第n个丑数是由这三个数中乘以对应值后的最小值。这时,另外两个数乘以对应值还是要大于第n个数,而被选中的那个数应该加一右移(应该注意可能存在多个数相等的情况,这时相等的数都需要右移,这样才能保证大于第n个数)。因此可以使用动态规划:
int nthUglyNumber(int n) {
int a=0,b=0,c=0;
vector<int> v;
v.push_back(1);
for (int i=1;i<n;i++)
{
int minn=min(2*v[a],min(3*v[b],5*v[c]));
if (minn==2*v[a])
a++;
if (minn==3*v[b]) //不能用else if,因为可能相等
b++;
if (minn==5*v[c])
c++;
v.push_back(minn);
}
for (int i=0;i<v.size();i++)
cout<<v[i]<<' ';
return v[v.size()-1];
}
时间复杂度:O(n)
空间复杂度:O(n)
方法二
利用最小堆,开始时将1加入堆中,然后每次取出堆中最小的元素,将其分别乘以2,3,5,然后将他们放入堆中,第k次取出的元素即第k大的数。但是可能将重复的元素加入堆中,因此需要利用set先去重。
int nthUglyNumber(int n) {
priority_queue<ll,vector<ll>,greater<ll> > q;
set<ll> s;
s.insert(1);
q.push(1);
for (int i=0;i<n;i++)
{
ll k=q.top();
if (i==n-1)
return k;
q.pop();
if (!s.count(2*k))
{
q.push(2*k);
s.insert(2*k);
}
if (!s.count(3*k))
{
q.push(3*k);
s.insert(3*k);
}
if (!s.count(5*k))
{
q.push(5*k);
s.insert(5*k);
}
//cout<<k<<endl;
}
return 1;
}
时间复杂度:O(nlgn)
空间复杂度:O(n)

浙公网安备 33010602011771号