寻找丑数(ugly number)

【问题】

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

【分析】

很自然的我们可以想到使用暴力解法,把1500个丑数从众多数中找出来,如何找出来呢?我们就要判断这个数是否只包含2,3,5这三个因子,我们就将这几个因子全都消除,这样最后如果为丑数,则结果必然为1,否则的话,结果必然不为1,下面是代码:

bool isUglynum(int num){
		while(num %2 == 0)
			num /=2;
		while(num%3 == 0)
			num /=3;
		while(num%5 == 0)
			num /=5;
		return num==1? true:false;
}

int uglyNum(int index){
	int num = 2;
	int i = 0;
	while(i <index){
		if(isUglynum(num))
			i++;
		num++;
	}
	return num-1;
}

那么,会不会有更简单的方法呢?这个方法的复杂度太高了,而且不断地运用除法,必然会导致算法效率低下。想到我们有时会用空间换取时间的方法提高算法的时间复杂度,那么这个是否也可以这样呢?我们是否可以先存储起来原来已经找打的丑数,然后再计算新的丑数呢?答案是肯定的,我们可以用一个数组按顺序储存起来原来找到的丑数,然后对已经找到的丑数计算它们乘以因子2,3,5,之后的结果,然后从中找到一个最小的,添加到数组后面,这样直到找到指定序号的丑数,代码如下:

int min(int x, int y,int z){
	int min = x;
	if(y < min)
		min = y;
	if(z < min)
		min = z;
	return min;
}


int uglyNum2(int index){
	int *array = new int[index + 1];
	int *pMin2 = array;
	int *pMin3 = array;
	int *pMin5 = array;
	
	int i = 0;
	array[0] = 1;
	while( i < index){
		array[++i] = min((*pMin2) * 2, (*pMin3) *3,(*pMin5)*5);
		while((*pMin2) * 2 <= array[i])
			pMin2++;
		while((*pMin3) * 3 <= array[i])
			pMin3++;
		while((*pMin5) * 5 <= array[i])
			pMin5++;
	}
	int ugly = array[i];
	delete array;
	return ugly;
}
点赞