欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

丑数问题

程序员文章站 2022-05-07 12:08:30
...

问题描述

2,3,5组成的数,即数由2,3,5因数组成,不含有其他因数.其中1是特殊的丑数.求第n个丑数.

[1,2,3,4,5,6,8,9,10,12,...].

分析

由于只由2,3,5三个因数组成,则可以对数进行因数分解,若只由2,3,5因数组成,则为丑数.从1开始进行循环寻找:

int uglyNum(int n) {
	int number = 1;					//从1开始
	int count = 0;						//计数
	while (1) {							//循环查找
		int num = number;			//用于因数分解
		while (num % 2 == 0) {	//是否可以被2因数分解
			num /= 2;
		}
		while (num % 3 == 0) {	//是否可以被3因数分解
			num /= 3;
		}
		while (num % 5 == 0) {	//是否可以被5因数分解
			num /= 5;
		}

		if (num == 1) {					//是否只能被2,3,5因数分解
			count++;						//是则计数加一
		}

		if (count == n) {				//第n个则跳出循环
			break;
		} else {
			number++;					//不是则继续循环
		}
	}

	return number;
}

这样的做法当n很大时,都要从1一直循环n次,很耗时,而且当中还有很多因数分解的过程.

再次分析

再次分析发现数组[1,2,3,4,5,6,8,9,10,12,...]
除了第一个丑数1,向后的丑数,都是由之前丑数x2,3,5得到的,并且丑数是一个递增的过程.
2=1x2,3=1x3,4=2x2,5=1x5,6=2x3
所以完全可以让之前的丑数x2,3,5,比较数值获取下一个丑数.

#define MAX 99999					//数组最大值
int uglyNum(int n) {
	int uglys[MAX] = {1};				//保存丑数数组
	int count = 1;							//因有一个数,所以从1开始
	//1的情况另做判断
	if (n == 1) {
		return 1;
	}
	while (1) {
		int chooseTwo = 0;				//记录和2相乘的数据
		int chooseThree = 0;			//记录和3相乘的数据
		int chooseFive = 0;				//记录和5相乘的数据
		for (int i = 0; i < count; i++) {					//循环前面丑数和2相乘
			if (uglys[i] * 2 > uglys[count - 1]) {		//找到第一个大于前一个的丑数,直接记录然后break
				chooseTwo = uglys[i] * 2;
				break;
			}
		}
		for (int i = 0; i < count; i++) {					//和2同理
			if (uglys[i] * 3 > uglys[count - 1]) {
				chooseThree = uglys[i] * 3;
				break;
			}
		}
		for (int i = 0; i < count; i++) {					//和2同理
			if (uglys[i] * 5 > uglys[count - 1]) {
				chooseFive = uglys[i] * 5;
				break;
			}
		}
		//比较三个数的大小,小的即为丑数,加入数组中
		int temp = chooseTwo <= chooseThree ? chooseTwo : chooseThree;
		uglys[count] = temp <= chooseFive ? temp : chooseFive;
		//计数器加一
		count++;
		//如果是第n个就直接返回
		if (count == n) {
			//数组最后一个元素下标是count-1
			return uglys[count - 1];
		}
	}
}

执行速度显著提高,空间换取时间的做法.

相关标签: 个人总结