C++求丑数直解

丑数描述

说法一:把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但7、14不是,因为它们包含质因子7。 习惯上我们把1当做是第一个丑数。

前20个丑数为:1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36。

说法二:对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S。这个正整数集合包括,p1、p1*p2、p1*p1、p1*p2*p3...(还有其它)。该集合被称为S集合的“丑数集合”。注意:我们认为1不是一个丑数,丑数集合中每个数从小到大排列,每个丑数都是素数集合中的数的乘积。(如S={2,3,5}时,对应丑数集合为U={2,3,4,5,6,9,10,15,25,30})

回复https://ask.csdn.net/questions/871981

void 查找丑数(int 求数)
{/*说法一:把只包含质因子2,3和5的数称作丑数。例如6、8都是丑数,但7、14不是,因为它们包含质因子7。 习惯上我们把1当做是第一个丑数。*/
	int 换 = 5;
	bool 判 = false;
	if (求数 % 2 == 0 || 求数 % 3 == 0 || 求数 % 5 == 0 || 求数 == 1)判 = true;
	while (换 < 求数)
	{
		换 += 2;
		if (换 % 3 == 0 || 换 % 5 == 0)continue;
		if (求数%换 == 0)
		{
			//cout << 求数 << "非丑" << 换 << "; ";// && 求数 != 换
			判 = false;
			break;
		}
	}
	if (判)cout << 求数 << "丑数" << "; ";
}

void 查找丑数(int 求数)
{/*说法一:把只包含质因子2,3和5的数称作丑数。例如6、8都是丑数,但7、14不是,因为它们包含质因子7。 习惯上我们把1当做是第一个丑数。*/
	int 换 = 5;
	bool 判 = false;
	if (求数 % 2 == 0 || 求数 % 3 == 0 || 求数 % 5 == 0)判 = true;
	while (判 && 换 < 求数)
	{
		换 += 2;
		if (换 % 3 == 0 || 换 % 5 == 0)continue;
		if (求数 % 换 == 0)
		{
			判 = false;//cout << 求数 << "非丑" << 换 << "; ";// 求数 != 换 && 
			break;
		}
	}
	if (判 || 求数 == 1)cout << 求数 << endl;//cout << 求数 << "丑数" << "; ";
}


int _tmain(int argc, _TCHAR* argv[])
{
起始:
	clock_t start = clock();
	int 数 = 1;
	while(数<=1400)查找丑数(数++);
	clock_t stop = clock();
	printf_s("耗时:%lf\n", (double)(stop - start) / CLOCKS_PER_SEC);

	//cout << endl;
	//CTime time(CTime::GetCurrentTime());
	//SYSTEMTIME timeDest;
	//time.GetAsSystemTime(timeDest);
	//int 年 = timeDest.wYear, 月 = timeDest.wMonth, 日 = timeDest.wDay;
	//char 时间[128];
	_strdate_s(时间, 128);
	//_strtime_s(时间, 128);
	printf("系统日期:%s\n", 时间);
	//阳历节日日历(时间, 年, 月, 日);

	system("pause");
	goto 起始;
	//return 0;
}

 

看过一些画蛇添足的直接求解程序,我这个直接求解程序使用的时间大为降低,效率大为提高。

bool 折半查找(int *数组, int 序, int 值)
{
	int 头 = 0, 尾 = 序 - 1;
	do
	{
		if (数组[尾] == 值)return true;
		if (数组[头] == 值)return true;

	} while (++头 <= --尾);
	return false;
}
int 获取大于5的验证集合以提高验证速度(int 求数, int* 验证集合)
{
	int 换 = 5;
	int 验序 = 0;
	while (换<求数 / 2)
	{
		换 += 2;
		if (换 % 3 != 0 && 换 % 5 != 0)验证集合[验序++] = 换;
	}
	return 验序;
}
void 丑数优化(int *验组, int 验序, int 求数)
{
	int 头 = 0, 尾 = 验序 - 1;
	bool 判 = false;
	if (求数 % 2 == 0 || 求数 % 3 == 0 || 求数 % 5 == 0)判 = true;
	while (判 && 头 < 尾)
	{
		if (求数 % 验组[头++] == 0 || 求数 % 验组[尾--] == 0)
		{
			判 = false;
			break;
		}
	}
	if (判 || 求数 == 1)cout << 求数 << endl;
}

double 最小时间 = 100000;
int _tmain(int argc, _TCHAR* argv[])
{
起始:

	int 数 = 1, 求数 = 100000, 序 = 0, 验证集合[100000 / 7] = { 0 };
	序 = 获取大于5的验证集合以提高验证速度(求数, 验证集合);
	clock_t start = clock();
	while (数 <= 求数)丑数优化(验证集合, 序, 数++);
	//while (数 <= 求数)查找丑数(数++);
	clock_t stop = clock();
	if ((double)(stop - start) / CLOCKS_PER_SEC < 最小时间)最小时间 = (double)(stop - start) / CLOCKS_PER_SEC;
	printf_s("耗时:%lf\n", 最小时间);

	//cout << endl;
	//CTime time(CTime::GetCurrentTime());
	//SYSTEMTIME timeDest;
	//time.GetAsSystemTime(timeDest);
	//int 年 = timeDest.wYear, 月 = timeDest.wMonth, 日 = timeDest.wDay;
	//char 时间[128];
	_strdate_s(时间, 128);
	//_strtime_s(时间, 128);
	printf("系统日期:%s\n", 时间);
	//阳历节日日历(时间, 年, 月, 日);

	system("pause");
	goto 起始;
	//return 0;
}

原算法与优化算法对比

最好的思路网络上有:方法二思路:后面的丑数肯定是已存在的丑数乘以2、3或者5,找到比现有丑数大的且是最小的丑数作为下一个丑数(如何找是关键)。用2分别从现有丑数中从前往后乘以丑数,找到第一个大于当前所有丑数的值以及位置,3、5同样如此,再把他们相乘之后的结果做对比,取最小的。下次将从上一次的位置开始往下找,这样将不会出现冗余。转录如下:

https://www.cnblogs.com/ys99/p/9307426.html

int Next_Ugly(int ugly_arr[], int *loc2, int *loc3, int *loc5, int *index) {
	while (ugly_arr[*loc2] * 2 <= ugly_arr[*index]) (*loc2)++;     //千万注意这里是小于等于,不要写成小于了
	while (ugly_arr[*loc3] * 3 <= ugly_arr[*index]) (*loc3)++;
	while (ugly_arr[*loc5] * 5 <= ugly_arr[*index]) (*loc5)++;
	if (ugly_arr[*loc2] * 2< ugly_arr[*loc3] * 3) return (ugly_arr[*loc2] * 2 < ugly_arr[*loc5] * 5) ? ugly_arr[*loc2] * 2 : ugly_arr[*loc5] * 5;
	else return (ugly_arr[*loc3] * 3) < ugly_arr[*loc5] * 5 ? ugly_arr[*loc3] * 3 : ugly_arr[*loc5] * 5;
}

int get_Ugly_sec(int num) {/*(2)方法二思路:后面的丑数肯定是已存在的丑数乘以2、3或者5,找到比现有丑数大的且是最小的丑数作为下一个丑数(如何找是关键)。用2分别从现有丑数中从前往后乘以丑数,找到第一个大于当前所有丑数的值以及位置,3、5同样如此,再把他们相乘之后的结果做对比,取最小的。下次将从上一次的位置开始往下找,这样将不会出现冗余。*/
	int ugly_arr[1000];
	int index = 0, value = 1;
	int loc2 = 0, loc3 = 0, loc5 = 0;
	while (value <= num) {
		ugly_arr[index] = value;
		cout << ugly_arr[index] << "\t";
		//if ((index + 1) % 10 == 0) cout << endl;
		value = Next_Ugly(ugly_arr, &loc2, &loc3, &loc5, &index);
		index++;
	}
	return index;
}
double 最小时间 = 100000;
int _tmain(int argc, _TCHAR* argv[])
{
	clock_t start = clock();
	get_Ugly_sec(1000000);
	clock_t stop = clock();
	if ((double)(stop - start) / CLOCKS_PER_SEC < 最小时间)最小时间 = (double)(stop - start) / CLOCKS_PER_SEC;
	printf_s("耗时:%lf\n", 最小时间);
}

更新程序:添加7即可实现H数;有么有2 3 5 7 9的,有的话,直接在我程序基础里面添加就是。

void 丑数(int 数)
{
	int Lin = 数;
	while (Lin>1)
	{
		if (!(Lin % 2) || !(Lin % 3) || !(Lin % 5))
		{
			if (!(Lin % 2))Lin /= 2;
			if (!(Lin % 3))Lin /= 3;//使用else的话就不是并行处理
			if (!(Lin % 5))Lin /= 5;
		}
		else return;
	}
	cout << 数 << ends;
}

int a = 1; while (++a <= 3000)丑数(a);

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值