版权声明:本文为博主NJU_ChopinXBP原创文章,发表于CSDN,仅供交流学习使用,转载请私信或评论联系,未经博主允许不得转载。感谢您的评论与点赞。 https://blog.csdn.net/qq_20304723/article/details/82967361
2018.10.8
这道丑数题有一个最直接的解法:对于从1开始的每一个数进行遍历,将该数按照丑数的定义,先循环除以5,直到无法整除;接着同样的方式整除3和2,直到无法整除,最后剩下的结果如果恰好为1,说明该数为丑数。因此理论上只要挨个验证丑数即可。
但是事实上却并不是这样,丑数增长是指数型的,第1500个丑数为859963392,如果从1开始遍历进行判断,哪怕逻辑再简单,程序时间效率也极低。因此我们考虑从丑数本身出发寻找规律。
第一个丑数为1,因子为2、3、5,按照丑数的定义,每一个丑数必定是由原有的丑数通过乘以2、3、5而来。因此我们可以定义一个丑数序列uglyNum(考虑插入删除的便捷,用LinkedList)和一个备选新丑数序列newugly(考虑到需要排序取最小且不能重复,用TreeSet),从newugly中将最小的备选丑数加入uglyNum,并且将该数与2、3、5的乘积分别作为新的备选丑数加入newugly即可。
中间需要注意的一个问题是int数据溢出问题,可以将所有数据类型改为long。考虑到本题要求数据不大,加一个循环除去溢出导致的负值即可。
题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
Java实现:
/**
*
* @author ChopinXBP
* 把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。
* 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
*
*/
import java.util.LinkedList;
import java.util.TreeSet;
public class GetUglyNumber_32 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(GetUglyNumber_Solution(1500));
}
public static int GetUglyNumber_Solution(int index) {
if(index <= 0) return 0;
if(index <= 6) return index; //0-6的丑数为其本身
LinkedList<Integer> uglyNum = new LinkedList<>(); //丑数顺序列
uglyNum.add(1);
TreeSet<Integer> newugly = new TreeSet<>(); //备选新丑数序列
newugly.add(2);
newugly.add(3);
newugly.add(5);
//每次循环将newugly中最小的丑数加入uglyNum,并将其的2、3、5倍数放入newugly
while(uglyNum.size() < index){
//不考虑大数,这段用来防止int的溢出,删去溢出的负数,可用long类型替代int
while(newugly.first() <= uglyNum.getLast()){
newugly.pollFirst();
}
int newuglynum = newugly.pollFirst();
newugly.add(newuglynum * 2);
newugly.add(newuglynum * 3);
newugly.add(newuglynum * 5);
uglyNum.add(newuglynum);
}
return uglyNum.getLast();
}
}
C++实现示例:
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if (index < 7)return index;
vector<int> res(index);
res[0] = 1;
int t2 = 0, t3 = 0, t5 = 0, i;
for (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];
}
};
测试用例:
// ====================测试代码====================
void Test(int index, int expected)
{
if(GetUglyNumber_Solution1(index) == expected)
printf("solution1 passed\n");
else
printf("solution1 failed\n");
if(GetUglyNumber_Solution2(index) == expected)
printf("solution2 passed\n");
else
printf("solution2 failed\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
Test(1, 1);
Test(2, 2);
Test(3, 3);
Test(4, 4);
Test(5, 5);
Test(6, 6);
Test(7, 8);
Test(8, 9);
Test(9, 10);
Test(10, 12);
Test(11, 15);
Test(1500, 859963392);
Test(0, 0);
return 0;
}
#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#