4.丑数2
首先了解一下什么是丑数,丑数的定义是,只包含质因子 2, 3, 5 的正整数。比如 6, 8 就是丑数,但是 14 不是丑数因为他包含了质因子 7。而判断一个整数是不是丑数则可以借鉴[517.丑数](http://www.cnblogs.com/yunlambert/p/8010871.html)。
那么这道题其实是让我们找出第n个丑数(包括1)
开始的思路自然是遍历,万宗不变遍历嘛,就有了以下代码:
class Solution {
public:
/*
* @param n: An integer
* @return: the nth prime number as description.
*/
int nthUglyNumber(int n) {
// write your code here
int count=0;
int max=100000000;
for(int i=1;i<=max;i++)
{
if(isUgly(i)) count++;
if(count==n) return i;
}
}
bool isUgly(int num) {
// write your code here
if (num <= 0)
return false;
while (num%2 == 0)
num = num / 2;
while (num%3 == 0)
num = num /3;
while (num%5 == 0)
num = num /5;
if (num == 1)
return true;
return false ;
}
};
但遗憾的是,在输入1665的时候提示超时了。。的确,遍历算法的缺点就在这里,所以需要对算法进行优化。这里推荐一篇博客面试题之丑数的C++实现求解,对于丑数的解法介绍的还是比较全面的。
我们知道丑数序列可以拆分为下面3个子列表:
(2) 1×2, 2×2, 3×2, 4×2, 5×2, …
(3) 1×3, 2×3, 3×3, 4×3, 5×3, …
(5) 1×5, 2×5, 3×5, 4×5, 5×5, …
一个新的丑数可以看做是一个旧的丑数乘以2,3,5得到的(第一个丑数是1,第二个为2,则第二个可以看做第一个丑数2得到了第二个丑数(12、13和15中的最小者)),本题解题难点在于维护丑数数列为从小到大排列的顺序。
根据上述思路可以做如下实现:
- 维护三个列表l2,l3,l5,分别是当前处理的丑数num的2,3,5倍,因此三个列表组内均是按照从小到大进行排列的;
- 每次获得三个列表的第一个结点(最小的结点)为当前丑数num,根据当前丑数值在三个列表末端插入新的较大的丑数值,等待后续处理;
- 若列表的第一个结点与当前丑数num相等,则删除列表第一个结点(表示该丑数已经被计数);
- 题目的初始条件为num = 1, count = 1;
class Solution {
public:
int nthUglyNumber(int n) {
int count = 1;
int num = 1;
list<int> l2;
list<int> l3;
list<int> l5;
while(count != n)
{
l2.push_back(2*num);
l3.push_back(3*num);
l5.push_back(5*num);
int l2min = l2.front();
int l3min = l3.front();
int l5min = l5.front();
int minNum = min(l2min, min(l3min, l5min));
if(l2min == minNum) l2.pop_front();
if(l3min == minNum) l3.pop_front();
if(l5min == minNum) l5.pop_front();
num = minNum;
++count;
}
return num;
}
};
对于乘以2而言,肯定存在某一个丑数t2,使得排在它之前的每一个丑数乘以2得到的结果都会小于已有最大丑数,在它之后的每个丑数乘以2得到的结果都会大于当前最大丑数。我们只需要记下这个丑数的位置,同时每次生成新的丑数时去更新这个t2。对于3和5,同样存在t3和t5。
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> uglyNumSeq(1, 1);
int i2 = 0, i3 = 0, i5 = 0;
while (uglyNumSeq.size() < n) {
int n2 = uglyNumSeq[i2] * 2;
int n3 = uglyNumSeq[i3] * 3;
int n5 = uglyNumSeq[i5] * 5;
int next = min(n2, min(n3, n5));
if (next == n2) ++i2;
if (next == n3) ++i3; //注意不用else if,因为不同序列可能有相同值
if (next == n5) ++i5;
uglyNumSeq.push_back(next);
}
return uglyNumSeq.back();
}
};
-------------------------------------------
个性签名:一名会音乐、爱健身的不合格程序员
可以Follow博主的Github哦(っ•̀ω•́)っ✎⁾⁾