劍指Offer(java版):醜數

題目:醜數
 * 咱們把只包含因子2,3,5的數稱爲醜數(Ugly Number).
 * 求按從小到大的順序的第1500個醜數。面試

 * 例如6,8都是醜數,但14不是,由於它含有因子7.習慣上咱們把1看成第一個醜數算法

方法一:逐個判斷每一個整數是否是醜數的解法,直觀但不夠高效:數組

所謂一個數m是另外一個數n的因子,是指n能被m整除,也就是說 n%m==0.根據醜數的定義,醜數只能被2,3,5整除。也就是說若是一個數能被2整除,咱們把它連續除以2;若是能被3整除,就連續除以3;若是能被 5整除,就除以5.若是最後咱們獲得的是1,那麼這個數就是醜數,不然不是。函數

接下來,咱們只須要按照順序判斷每一個整數是否是醜數,this

適用Java代碼實現:.net

 

 

package cglib;排序


public class jiekou {內存

       public boolean isUgly(int number){
           //System.out.println("進入isUgly");
            while(number % 2 == 0)  
                 {
                //System.out.println("number模2爲0="+number);
                   number/=2;
                //System.out.println("number整除2後="+number);
                 
                 }
            while(number % 3 == 0)  
                number /=3;  
            while(number % 5 == 0)  
                number /=5;
            
            //System.out.println("最後number="+number);
            return (number ==1)? true:false;  
        }  
        public int getUglyNumber(int index){
            
            if(index <= 0)  
                return 0;  
            int number = 0;  
            int uglyFound = 0;
           // System.out.println("index="+index);
            while(uglyFound < index){
                //System.out.println("uglyFound="+uglyFound);
                number++;
                //System.out.println("number="+number);
                if(isUgly(number)){  //從1開始
                    ++uglyFound;
                    //System.out.println("++uglyFound="+uglyFound);
                }  
            }  
            return number;  
        }  
        public static void main(String[] args){  
            int index = 150;  
            jiekou test = new jiekou();  
            System.out.println(test.getUglyNumber(index));  
        }
    }get

 

咱們只須要在函數getUglyNumber 中傳入參數1500,就能獲得第1500個醜數。該算法很是直觀,代碼也很是簡介,但最大的問題是每一個整數都須要計算。即便一個數字不是醜數,咱們仍是需 要對它作求餘和除法操做。所以該算法的時間效率不是很高,面試官也不會就此知足,還會提示咱們有更高效的算法。class

 

方法二:建立數組保存已經找到的醜數,用空間換時間的解法:

前面的算法之因此效率低,很大程度上是由於無論一個數是否是醜數咱們 對它都要做計算。接下來咱們試着找到一種只要計算醜數的方法,而不在非醜數的整數上花費時間。根據醜數的定義,醜數應該是另外一個醜數乘以2,3,5的結 果。所以咱們能夠建立一個數組,裏面的數字是排序好的醜數,每個醜數都是前面的醜數乘以2,3,5獲得的。

這種思路的關鍵在於怎樣肯定數組裏面的醜數是排序好的。假設數組中已 經有若干個醜數排好後存放在數組中,而且把已有的最大的醜數記做M,咱們接下來分析如何生成下一個醜數。該醜數確定是前面某個醜數乘以2,3,5的結果。 因此咱們首先考慮把已有的每一個醜數乘以2.在乘以2的時候,能獲得若干個小於或等於M的結果。因爲是按照順序生成的,小於或者等於M確定已經在數組中了, 咱們不須要再次考慮;還會獲得若干個大於M的結果,但咱們只須要第一個大於M的結果,由於咱們但願醜數是指按從小到大的順序生成的,其餘更大的結果之後再 說。咱們把獲得的第一個乘以2後大於M的結果即爲M2.一樣,咱們把已有的每個醜數乘以3,5,能獲得第一個大於M的結果M3和M5.那麼下一個醜數應 該是M2,M3,M5。這3個數的最小者。

前面分析的時候,提到把已有的每一個醜數分別都乘以2,3,5.事實上 這不是必須的,由於已有的醜數都是按順序存放在數組中的。對乘以2而言,確定存在某一個醜數T2,排在它以前的每個醜數乘以2獲得的結果都會小於已有的 最大丑數,在它以後的每個醜數乘以2獲得的結果都會太大。咱們只需記下這個醜數的位置,同時每次生成新的醜數的時候,去更新這個T2.對乘以3和5而 言,也存在這一樣的T3和T5.

Java代碼實現:

package cglib;


public class jiekou {

     /*****
      *
      * 程序中採用double的緣由是:由於int型表示數據範圍有限倒置數據溢出,unsigned long int 仍然溢出三者的表示的數據範圍以下:
int max --> 2147483647    在第1692個醜數越界
unsigned long int max --> 4294967295  在第1849個醜數越界
double max --> 1.79769e+308
      * @param a
      * @param b
      * @param c
      * @return
      */
    private double findTheMinNumber(double a,double b,double c){
        //找到a,b之間最小的
        double temp = a < b ? a : b;
        //找到abc之間最小的返回
        return temp < c ? temp : c;
    }
   
   
  

       private double findUgly(int n){
        if(n<0)
            return 0;
        double[] ugly = new double[n];       
        ugly[0] = 1;      
        int index = 1;      
        int index2 = 0;
        int index3 = 0;
        int index5 = 0;          
        while(index < n){
            double var = this.findTheMinNumber(ugly[index2]*2, ugly[index3]*3, ugly[index5]*5);//找到這三個數的最小值
            if (var == ugly[index2]*2) {
                ++index2;
            }
            if (var == ugly[index3]*3) {
                ++index3;
            }           
            if (var == ugly[index5]*5) {
                ++index5;
            }
            System.out.println("var="+var);
            ugly[index++] = var;//將比較後最小的醜數放到數組裏
            System.out.println("index="+index);
        }
       
        //循環輸出全部的醜數
        for (int i = 1; i <= ugly.length; i++) {
          
            System.out.println("the "+i+" th ugly number is "+ugly[i-1]);
        }
        return ugly[index-1];//返回的是最後一個醜數
    }
   
   
    public static void main(String[] args) {
        jiekou find  = new jiekou();
        find.findUgly(2012);
      }
     }

輸出:

var=3.9366E9
index=1829
var=3.955078125E9
index=1830
var=3.981312E9
index=1831
var=3.9858075E9
index=1832
var=4.0E9
index=1833
var=4.02653184E9
index=1834
var=4.0310784E9
index=1835
var=4.05E9
index=1836
var=4.076863488E9
index=1837
var=4.08146688E9
index=1838
var=4.096E9
index=1839
var=4.100625E9
index=1840
var=4.132485216E9
index=1841
var=4.1472E9
index=1842
var=4.194304E9
index=1843
var=4.19904E9
index=1844
var=4.21875E9
index=1845
var=4.2467328E9
index=1846
var=4.251528E9
index=1847
var=4.271484375E9
index=1848
var=4.294967296E9
index=1849
var=4.29981696E9
index=1850
var=4.3046721E9
index=1851
var=4.32E9
index=1852
var=4.353564672E9
index=1853
var=4.374E9
index=1854
var=4.39453125E9
index=1855
var=4.42368E9
index=1856
var=4.428675E9
index=1857
var=4.478976E9
index=1858
var=4.5E9
index=1859
var=4.52984832E9
index=1860
var=4.5349632E9
index=1861
var=4.55625E9
index=1862
var=4.586471424E9
index=1863
var=4.59165024E9
index=1864
var=4.608E9
index=1865
var=4.613203125E9
index=1866
var=4.649045868E9
index=1867
var=4.6656E9
index=1868
var=4.6875E9
index=1869
var=4.718592E9
index=1870
var=4.72392E9
index=1871
var=4.74609375E9
index=1872
var=4.7775744E9
index=1873
var=4.782969E9
index=1874
var=4.8E9
index=1875
var=4.831838208E9
index=1876
var=4.83729408E9
index=1877
var=4.86E9
index=1878
var=4.8828125E9
index=1879
var=4.897760256E9
index=1880
var=4.9152E9
index=1881
var=4.92075E9
index=1882
var=4.97664E9
index=1883
var=4.982259375E9
index=1884
var=5.0E9
index=1885
var=5.0331648E9
index=1886
var=5.038848E9

。。。。。。。。

 

the 149 th ugly number is 5760.0
the 150 th ugly number is 5832.0
the 151 th ugly number is 6000.0
the 152 th ugly number is 6075.0
the 153 th ugly number is 6144.0
the 154 th ugly number is 6250.0
the 155 th ugly number is 6400.0
the 156 th ugly number is 6480.0
the 157 th ugly number is 6561.0
the 158 th ugly number is 6750.0
the 159 th ugly number is 6912.0
the 160 th ugly number is 7200.0
the 161 th ugly number is 7290.0
the 162 th ugly number is 7500.0
the 163 th ugly number is 7680.0
the 164 th ugly number is 7776.0
the 165 th ugly number is 8000.0
the 166 th ugly number is 8100.0
the 167 th ugly number is 8192.0
the 168 th ugly number is 8640.0
the 169 th ugly number is 8748.0
the 170 th ugly number is 9000.0
the 171 th ugly number is 9216.0
the 172 th ugly number is 9375.0
the 173 th ugly number is 9600.0
the 174 th ugly number is 9720.0

 

。。。。。。。。。。。。。。

 

the 2006 th ugly number is 8.264970432E9
the 2007 th ugly number is 8.2944E9
the 2008 th ugly number is 8.303765625E9
the 2009 th ugly number is 8.388608E9
the 2010 th ugly number is 8.39808E9
the 2011 th ugly number is 8.4375E9
the 2012 th ugly number is 8.4934656E9

和第一種思路相比,第二種思路不須要在非醜數的整數上作任何計算,所以時 間效率有明顯上升。但也須要指出,第二種算法因爲須要保存已經生成的醜數,所以須要一個數組,從而增長了空間消耗。若是是求第1500個醜數,將建立一個 能容納1500個醜數的數組,這個數組佔內存6KB。而第一種思路沒有這樣的內存開銷。總的來講,第二種思路至關於用較少的空間換取了時間效率上的提高。

相關文章
相關標籤/搜索