剑指offer| |丑数

题目:我们把只包含因子2、3和5的数称为丑数(Ugly Number)。求按从小到大的顺序的第1500个丑数。例如6是丑数,但14不是,因为它包含因子7.习惯上我们把1当做第一个丑数。

方法一:
思路:逐个判断每个整数是不是丑数
依次从1开始判断每个数是不是丑数,从而求出第1500个丑数,

这种方法思路简单但是不够高效。

代码:

//是丑数 1
//不是 0
int CheckUglyNumber(int num)
{
	assert(num >= 0);

	while (num % 2 == 0)
	{
		num /= 2;
	}

	while (num % 3 == 0)
	{
		num /= 3;
	}

	while (num % 5 == 0)
	{
		num /= 5;
	}
	
	return (num == 1) ? 1 : 0;
}
		
int UglyNumber1(int num)
{
	assert(num >= 0);

	int order = 0;//判断是否是丑数
	int count = 0;//记录丑数的个数

	while (count < num)
	{
		order++;

		if (CheckUglyNumber(order))
		{
			count++;
		}
	}

	return order;
}

方法二:
创建数组保存已经找到的丑数(用空间换时间的做法)

前面的算法之所以效率低,很大程度上是因为这个数是不是丑数都要对其进行计算判断其实不是丑数。
接下来这种方法,我们不再对非丑数的整数上浪费时间。根据丑数的定义,丑数应该是另外一个丑数乘以2、3或5的结果(1除外),因此我们可以创建一个数组,里面的数是排好顺序的丑数,每一个丑数都是前面的丑数乘以2、3或者5得到的。

这种思路关键在于怎样确保数组里面的丑数是排好序的。
假设数组中已经有若干个丑数排好序存在数组中,并且已有最大的丑数记为M,我们接下来分析如何生成下一个丑数,该丑数肯定是前面丑数某一个丑数乘以2、3或者5的结果,所以我们首先考虑把已有的丑数乘以2.在乘以2的时候,能得到若干个小于或者等于M的结果。由于是按照顺序生成的,小于或者等于M肯定已经在数组中了,我们不需要再次考虑;还会得到若干个大于M的结果,但我们只需要第一个大于M的结果,但我们只需要第一个大于M的结果,因为我们希望丑数是按照从小到大的顺序生成的,其他更大的结果以后再说。我们把第一个乘以2后大于M的结果记为M2。同样第一个乘以3大于M的结果记为M3,乘以5得到的记为M5,那么下一个丑数应该是M2、M3、M5中的最小值。

创建一个空间为所能容纳要求的的丑数的个数。

代码:

int Min(int uglyMul2, int uglyMul3, int uglyMul5)
{
	int min = uglyMul2 > uglyMul3 ? uglyMul3 : uglyMul2;

	return min > uglyMul5 ? uglyMul5 : min;
}

int UglyNumber(int num)
{
	assert(num >= 0);

	int ugly_arr[MAXSIZE] = { 0 };
	int next_ugly_num = 1;
	ugly_arr[0] = 1;//第一个丑数是1

	int* uglyMul2 = &ugly_arr[0];
	int* uglyMul3 = &ugly_arr[0];
	int* uglyMul5 = &ugly_arr[0];

	while (next_ugly_num < num)
	{
		ugly_arr[next_ugly_num] = Min(*uglyMul2 * 2, *uglyMul3 * 3, *uglyMul5 * 5);

		while (*uglyMul2 * 2 <= ugly_arr[next_ugly_num])
		{
			uglyMul2++;
		}

		while (*uglyMul3 * 3 <= ugly_arr[next_ugly_num])
		{
			uglyMul3++;
		}

		while (*uglyMul5 * 5 <= ugly_arr[next_ugly_num])
		{
			uglyMul5++;
		}

		next_ugly_num++;
	}

	return ugly_arr[num - 1];
}

猜你喜欢

转载自blog.csdn.net/qq_40399012/article/details/82820964