丑数

求按从小到大的顺序的第N个丑数

Posted by DH on July 18, 2017

题目

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

要判断一个数是不是丑数,最简单的就是用下面这个函数进行遍历:

public bool isUglyNumber(int input){
  while(input%2==0){
      input/=2;
  }
  
   while(input%3==0){
      input/=3;
  }
  
   while(input%5==0){
      input/=5;
  }
  
  if(input == 1){
      return true;
    }else{
      return false;
    }
}

分析

假如我们用上面的方法,从1开始进行遍历,每遍历一个数就进行判断,是丑数就添加进一个丑数数组,直到满足丑数数组的长度是N。最后输出最后一个数就是结果。

但是如果N太大,就需要判断很多不是丑数的数,效率不高。

而我们知道,丑数的定义可以简单的看做一个公式2^x3^y5^.因此,一个丑数乘以2的倍数,3的倍数,5的倍数之后也是丑数,那么我们就可以从头开始,直接找到丑数并 添加到丑数数组,直到丑数数组的长度是N。

具体来说:

例如目前丑数数组中只有1

那么 21=2,21=3,5*1=5;

我们选最小的放到丑数数组侯曼,这时候,丑数数组是{1,2}。

按照这种思想,

每增加一个丑数,需要进行比较的数就增加3,这个时候有:31=3,51=5; 21=2,23=6,5*2=10;

我们依旧选最小的是3,按照这种方式,每增加一个丑数,就要增加三个新的丑数进行判断。过于暴力。

假如我们只去记录2,3,5被选取时对应的丑数的下标,下一次比较的时候,我们只去比较这三个数,选取最小的,下标前移一个单位。 这样就永远只需要比较三个数。

代码

public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if (index < 1) {
			return 0;
		}
		 
		 int count = 0;
		 
		 int [] ugltNumbers = new int[index];
		 
		 ugltNumbers[0] = 1;
		 
		 // 2.3.5对应的要乘的最小数的索引
		 int i2 = 0;
		 int i3 = 0;
		 int i5 = 0;
		 
		 
		 while (count < index-1) {
			
			 int tempResult = min(ugltNumbers[i2] * 2, ugltNumbers[i3] * 3, ugltNumbers[i5] * 5);
			
			if (tempResult == ugltNumbers[i2] * 2) {
				i2++;
			}
			
			if (tempResult == ugltNumbers[i3] * 3) {
				i3++;
			}
			
			if (tempResult == ugltNumbers[i5] * 5) {
				i5++;
			}
			
			 ugltNumbers[++count] = tempResult;
		}
		 
		 return ugltNumbers[ index - 1];
	 }
	 
	 // 找出三个数中最小的那个
	 public int min(int x,int y ,int z){
		
		if (x>y) {
			x=y;
		}
			return x>z?z:x;
		 
	 }
}