题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
总结:
”只包含质因子2、3、5的数称作丑数”,说明丑数都是由这三个基数相乘而来。
An ugly number must be multiplied by either 2, 3, or 5 from a smaller ugly number.
每一个新的丑数由一个更小的丑数乘以2、3、5得到。所以可以想象三个“链表”和三指针,第一个链表只做乘2操作,第二个乘3、第三个乘5。
定义一个vector来存放已经生成的丑数,题目给出第一个丑数为1。
(1) 1x2, 2x2, 2x2, 3x2, 3x2, 4x2, 5x2
(2) 1x3, 1x3, 2x3, 2x3, 2x3, 3x3, 3x3
(3) 1x5, 1x5, 1x5, 1x5, 2x5, 2x5, 2x5
min 2 3 4 5 6 ......
对应的数组(1,2,3,4,5,6,...)
丑数1可以根据乘以2,乘以3,乘以5,分别得到三个不同的丑数,因为题目给出“按照从小到大的顺序”,所以我们每一步只能抉择出一个新的丑数,选择min(2,3,5)最小的一个作为新的丑数,即2,添加到数组之中[1,2],此时1这个丑数已经用基数 2 生成了新的丑数,指针位置向后挪动一位,index2++ ; 但是此时1这个丑数,对应的基数3,5并没有生成新的丑数,所以仍然保留,即链表2和链表3的丑数不改变(对应的指针位置不改变),下一次循环,三个链表生成的新丑数为min(4,3,5),即链表2产生的3添加到丑数数组之中,丑数数组变成[1,2,3],此时链表2一开始对应的丑数1已经使用过了,应该向后挪动一位,改用丑数2.同理循环下去。要注意,因为肯定会出现生成的某个新丑数和两个链表产生的丑数相等:也就是2*3,3*2,这种情况。如果我们用if...else...则会引起重复,所以条件的判断是if...if...if...如果某个链表产生的丑数和选中的最小丑数一致,就应该把当前指针向后挪动一位;选取数字乘以基础是从丑数数组中选,而不是加一,如下图就是错误的:
一开始计算的都是正确的,因为丑数数组正好是累加增长,但是后面选取7,7X2 = 14就不是丑数了,所以是从丑数数组中选取。
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if(index == 0) return 0;
vector<int> res{1};
int index2 = 0,index3 = 0,index5 = 0;
while(res.size() != index){
int a = res[index2] * 2 , b = res[index3] * 3,c = res[index5] *5;
int min_val = min(a,min(b,c));
if(a == min_val) index2++;
if(b == min_val) index3++;
if(c == min_val) index5++;
res.push_back(min_val);
}
return res.back();
}
};