剑指offer-49:丑数

这道题的题目可以描述为:我们只把包含因子2,3,5的数称为丑数。求按小到大的顺序的第1500个丑数。

根据丑数的定义,一个数如果能被2整除,则连续除以2;一个数如果能被3整除,则连续除以3;一个数如果能被5整除,则连续除以5。如果最后得到的结果是1就是丑数,然后按照顺序判断每个数是不是丑数即可。

代码如下:

int IsUgly(int number)
{
	while (number % 2 == 0)
	{
		number /= 2;
	}
	while (number % 3 == 0)
	{
		number /= 3;
	}
	while (number % 5 == 0)
	{
		number /= 5;
	}
	return (number == 1) ? 1 : 0;
}
//求丑数1
int GetUglyNumber1(int index)
{
	if (index <= 0)
	{
		return 0;
	}
	int number = 0;
	int uglyFound = 0;
	while (uglyFound < index)
	{
		++number;
		if (IsUgly(number))
		{
			++uglyFound;
        }
	}
	return number;
}

但这种算法实现时间效率低,有一部分时间花费在非丑数的整数上面。下面介绍另一种算法。首先创建一个数组,数组里面的数是已经排好的丑数,每一个丑数都是前面的乘以2、3或者5得到的。

这个数组中丑数按升序排放,并把已有最大的丑数记为M。对于生成下一个丑数,可以把已有的每个丑数乘以2,会得到一些小于,等于或大于M的数,对于小于或等于M的数不需要再考虑,其已在数组中有序排列。只需要第一个大于M的结果,将其记为M2。同样,把已有的丑数乘以3和5,都能得到第一个大于M的数M3和M5。那么下一个丑数就是M2,M3,M5里面最小的一个。

对于乘以2而言,肯定存在一个数T2,它之前的每一个数乘以2都小于M,它之后的肯定都大于M。我们标记这个位置,每次只需要给它之前的数乘以2,同时每次生成新的丑数的时候更新这个位置即可。同理对于3和5而言,也存在着T3和T5。

代码如下:

int Min(int number1, int number2, int number3)
{
	int min = (number1 < number2) ? number1 : number2;
	 min = (min < number3) ? min : number3;
	 return min;
}
//求丑数2
int GetUglyNumber2(int index)
{
	if (index <= 0)
	{
		return 0;
	}
	//用来存放丑数数组
	int  *puglyNubmers; 
	puglyNubmers = (int*)malloc(sizeof(int)*index);
	if (puglyNubmers != NULL)
	{
		for (int i = 0; i < index; i++)
		{
			*(puglyNubmers + i) = 0;
		}
	}
	*puglyNubmers = 1;
	//下一个生成的丑数
	int nextUglyIndex = 1;
	//即T2(T2*2==目前数组中最大的丑数)
	int *pMultiply2 = puglyNubmers;
	//T3
	int *pMultiply3 = puglyNubmers;
	//T4
	int *pMultiply5 = puglyNubmers;
	while (nextUglyIndex < index)
	{
		int min = Min(*pMultiply2 * 2, *pMultiply3 * 3, *pMultiply5 * 5);
		puglyNubmers[nextUglyIndex] = min;
		while (*pMultiply2 * 2 <= puglyNubmers[nextUglyIndex])
		{
			++pMultiply2;
		}
		while (*pMultiply3 *3 <= puglyNubmers[nextUglyIndex])
		{
			++pMultiply3;
		}
		while (*pMultiply5 * 5 <=puglyNubmers[nextUglyIndex])
		{
			++pMultiply5;
		}
		++nextUglyIndex;
	}
	int ugly = puglyNubmers[nextUglyIndex-1];
	free(puglyNubmers);
	puglyNubmers = NULL;
	return ugly;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值