寻找丑数问题 HDOJ 1058 Humble Numbers

这是题目描述。

 

这道题目曾经也是Google、Hulu的一道面试题。对于这道题目,关键是要能够想到这一点:即对于任意一个丑数f[i],它都是由它前面的丑数乘以2,3,5或者7得到的。那么如果我们已经得到f[0] 到 f[i],怎样才能得到f[i+1]呢? 

 

可能你会怎么想(我刚开始也是这么想的)。我们已经有第一个丑数f[1] = 1,那么就设一个游标i=1指向f[1],然后依次将2,3,5,7与f[i]相乘,即我们可以得到2,3,5,7,然后依次将这些丑数加入到f[i]中,f[2] = 2, f[3] = 3, f[4] = 5, f[5] = 7,接着讲游标i++指向2,再分别于2,3,5,7相乘,即可以得到f[6] = 4, f[7] = 6, f[8] = 10, f[9] = 14。按照这种算法算下去,直到丑数的个数累计到了5842个。 仔细再想,我们会发现这种算法有两个问题,第一:所得的丑数数组是乱序的,即我们还需要对其进行排序,不过这个问题不大;更为严重的问题是数组中存在重复的丑数:前面我们已经得到了f[7] = 6,如果按以上算法继续算下去的话,很容易我们也可以得到f[10] = f[3] * 2= 6.所以我们排序完成之后要将数组中重复的数组去掉,去除完了之后又要进行新一轮的迭代,来使丑数数组中的不重复丑数达到5842个以上,很显然这个是很难用程序去控制的,因为我们需要事先计算出数组到底有多少重复的丑数,不过按照这个规律的话应该是可以算出来,不过我还没想到怎么算。^_^

 

那么有更好的解决方案吗? 这里给出了一个比较好的解决办法。 :

即定义四个游标,我们记为pos1,pos2,pos3,pos4 ,初始均为1. 这四个游标分别跟踪着对应的丑数乘以2,3,5,7所得的值。我们已经看到了方法一会给我们带来乱序和丑数重复的问题,方法二可以很好地解决这两个问题。 我们由一中的分析已经得到了f[i+1]是由f[1]到f[i]中的某个数乘以2,3,5,7中的某个数得来的。具体解法见以下代码,需要注意的是,arr[i]中可能会有两个同样的值是最小的,下面这小段代码解决了方法一中遇到的丑数重复的问题。

[cpp]  view plain copy
  1. <span style="white-space:pre">        </span>for(int j=0; j<N; j++)  
  2.             if(flag[j])  
  3.                 pos[j]++;  

 

 

 

对其进行了简单的修改,当然解题思想是参考该作者的。

[cpp]  view plain copy
    1. #include<iostream>  
    2. #include<string>  
    3. using namespace std;  
    4.   
    5. int const N = 4;  
    6. int map[N] = {2,3,5,7};  
    7.   
    8. int findMin(int arr[], bool flag[], int len)  
    9. {  
    10.     int min = arr[0];  
    11.     int i=0;  
    12.     for(i=0; i<len; i++)  
    13.         if(arr[i] < min)  
    14.             min = arr[i];  
    15.     for(i=0; i<len; i++)  
    16.     {  
    17.         if(min == arr[i])  
    18.             flag[i] = true;  
    19.         else  
    20.             flag[i] = false;  
    21.     }  
    22.       
    23.     return min;  
    24. }  
    25.   
    26.   
    27. void initHumble(int maxN, int humble[])  
    28. {  
    29.     humble[1] = 1;  
    30.     int pos[N] = {1,1,1,1};  
    31.     int arr[N];  
    32.     bool flag[N];  
    33.   
    34.     for(int i=2; i<=maxN; i++)  
    35.     {  
    36.   
    37.         for(int j=0; j<N; j++)  
    38.             arr[j] = humble[pos[j]]*map[j];  
    39.   
    40.         int min = findMin(arr, flag, N);  
    41.         humble[i] = min;  
    42.         for(int j=0; j<N; j++)  
    43.             if(flag[j]) //相同的最小丑数在这里会被过滤掉  
    44.                 pos[j]++;  
    45.           
    46.     }  
    47. }  
    48.   
    49. void outPut(int humble[])  
    50. {  
    51.     int n;  
    52.   
    53.     while(cin>>n && n)  
    54.     {  
    55.         string str = "th";  
    56.         if(n%10==1 && n%100!=11)  
    57.             str = "st";  
    58.         else if(n%10==2 && n%100!=12)  
    59.             str = "nd";  
    60.         else if(n%10==3 && n%100!=13)  
    61.             str = "rd";  
    62.   
    63.         cout<<"The "<<n<<str<<" humble number is "<<humble[n]<<"."<<endl;  
    64.     }  
    65. }  
    66.   
    67. int main()  
    68. {  
    69.     const int SIZE = 6000;  
    70.   
    71.     int humble[SIZE];  
    72.   
    73.     initHumble(5842, humble);  
    74.       
    75.     outPut(humble);  
    76.   
    77.     return 0;  
    78. }  

你可能感兴趣的:(number)