#数据结构与算法学习笔记#剑指Offer31:丑数 + 测试用例(Java、C/C++)

版权声明:本文为博主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一秒钟。留个言点个赞呗,谢谢你#

猜你喜欢

转载自blog.csdn.net/qq_20304723/article/details/82967361