剑指Offer----面试题34:丑数

题目:


我们把只包含因子2、3和5的数成为丑数,求按从小到大的顺序的第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做第一个丑数。


方法一:


分析:逐个判断整数是不是丑数,直观但是效率低下。


根据丑数的定义,丑数只能被2、3和5整除,也就是说一个数能被2整除,我们把它连续除以2;如果能被3整除,我们将它连续除以3;如果能被5整除,我们将它连续除以5;。如果自后得到1,那么这个数就是丑数。

代码如下:

#include<iostream>
#include<Windows.h>

using namespace std;

//判断一个数是否为丑数
bool isUgly(int num)
{
	if (num <= 0)
		return false;
	while (num % 2 == 0)
		num /= 2;
	while (num % 3 == 0)
		num /= 3;
	while (num % 5 == 0)
		num /= 5;

	return (num == 1) ? true : false;
}

int GetUglyNum(int index)
{
	if (index <= 0)
		return 0;

	int num = 0;//统计个数
	int temp = 0;//从第1个数开始判断

	while (num < index)
	{
		++temp;
		if (isUgly(temp))
			++num;
	}

	return temp;
}

int main()
{
	DWORD start = GetTickCount();
	cout << GetUglyNum(1500) << endl;
	DWORD used = GetTickCount() - start;
	cout << "耗时:" << used << "毫秒" << endl;

	system("pause");
	return 0;
}

运行结果:

859963392
耗时:38017毫秒
请按任意键继续. . .


注意:这种方法直观,代码简洁,但是最大的问题就是每一个整数都需要计算,因此效率低下。


方法二:





源代码如下:

#include<iostream>
#include<Windows.h>

using namespace std;

int Min(int num1, int num2, int num3)//返回三个数中最小值
{
	return (num1 < num2) ? ((num1 < num3) ? num1 : num3) : ((num2 < num3) ? num2 : num3);
}

int GetUglySolution2(int index)
{
	if (index <= 0)
		return 0;

	int *pUglyNumbers = new int[index];//申请内存空间,用来存储丑数
	memset(pUglyNumbers, 0, index);//将内存中原始数据置为0
	pUglyNumbers[0] = 1;//第一个丑数为1
	int nextUglyIndex = 1;

	int *M2 = pUglyNumbers;//*M2记录乘以2后的值,M2记录位置,初始时位置相同
	int *M3 = pUglyNumbers;
	int *M5 = pUglyNumbers;

	while (nextUglyIndex < index)
	{
		int min = Min((*M2) * 2, (*M3) * 3, (*M5) * 5);
		pUglyNumbers[nextUglyIndex] = min;//记录当前最大的丑数

		//对位置进行重新定位
		while (*M2 * 2 <= pUglyNumbers[nextUglyIndex])
			++M2;//记录下第一次大于当前最大丑数的M2的位置
		while (*M3 * 3 <= pUglyNumbers[nextUglyIndex])
			++M3;
		while (*M5 * 5 <= pUglyNumbers[nextUglyIndex])
			++M5;

		++nextUglyIndex;
	}

	int ugly = pUglyNumbers[nextUglyIndex - 1];
	delete[] pUglyNumbers;
	return ugly;
}

int main()
{
	DWORD start = GetTickCount();
	cout << GetUglySolution2(1500) << endl;

	DWORD used = GetTickCount() - start;
	cout << "耗时:" << used << "毫秒" << endl;

	system("pause");
	return 0;
}

运行结果:

859963392
耗时:0毫秒
请按任意键继续. . .

分析:

第二种方法效率明显提升,但是其消耗了1500*4*1024 = 6KB的存储空间。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值