264.Ugly Number II(Medium)

Write a program to find the n-th ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.

Note that 1 is typically treated as an ugly number.

Hint:

  1. The naive approach is to call isUgly for every number until you reach the n<sup style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; top: -0.5em;">th one. Most numbers are not ugly. Try to focus your effort on generating only the ugly ones.
  1. An ugly number must be multiplied by either 2, 3, or 5 from a smaller ugly number.
  2. The key is how to maintain the order of the ugly numbers. Try a similar approach of merging from three sorted lists: L<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">1, L<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">2, and L<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">3.
  3. Assume you have U<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">k, the k<sup style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; top: -0.5em;">th ugly number. Then U<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">k+1 must be Min(L<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">1 * 2, L<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">2 * 3, L<sub style="box-sizing: border-box; position: relative; font-size: 12px; line-height: 0; vertical-align: baseline; bottom: -0.25em;">3 * 5).

  題意就不翻譯了,意思就是把丑數(shù)從小到大排列,輸出制定位置的那個(gè)丑數(shù)是多少,按照上一題的那種樸素判斷當(dāng)然是行得通的,只要把1~n的數(shù)全部都驗(yàn)證一遍,自然可以找到第n個(gè),但是認(rèn)真想想,一旦n大了之后,其實(shí)丑數(shù)的個(gè)數(shù)是不多的,也就是說驗(yàn)證成功的次數(shù)遠(yuǎn)遠(yuǎn)小于失敗的,所以用樸素的驗(yàn)證方式,顯然是相當(dāng)浪費(fèi)時(shí)間(事實(shí)上也是),所以我們的思路就是想到如何一個(gè)一個(gè)計(jì)算出丑數(shù),找到其中的規(guī)律,主動(dòng)去計(jì)算丑數(shù)而不是被動(dòng)得驗(yàn)證是不是丑數(shù)

My Solution

(Java) Version 1 Time: 131ms:

  計(jì)算丑數(shù)的原理當(dāng)然不難,不要想到這一點(diǎn)還是花了不少功夫,首先每個(gè)丑數(shù)都是由2,3,5相乘得來的,而且每一個(gè)相同乘數(shù)的個(gè)數(shù)還不定,比如有5個(gè)5,3個(gè)1之類的,所以只能從小到大一個(gè)一個(gè)算出來,然后我們又發(fā)現(xiàn)了每個(gè)丑數(shù)其實(shí)都是由前面小的丑數(shù)乘以2,3,5得來的,那就很明顯了,我們只要把前面的丑數(shù)都乘以2,3,5,然后結(jié)果里面最小的那個(gè)就一定是下一個(gè)丑數(shù)了

public class Solution {
    public int nthUglyNumber(int n) {
        int[] nums = new int[n];
        nums[0]=1;
        int max2=0,max3=0,max5=0,index;
        for(int i=0;i<n-1;i++){
            index=0;
            while(max2<=nums[i]){
                max2=nums[index]*2;
                index++;
            }
            index=0;
            while(max3<=nums[i]){
                max3=nums[index]*3;
                index++;
            }
            index=0;
            while(max5<=nums[i]){
                max5=nums[index]*5;
                index++;
            }
            nums[i+1]=max2<max3?max2<max5?max2:max5<max3?max5:max3:max3<max5?max3:max5;
        }
        return nums[n-1];
    }
}

(Java) Version 2 Time: 46ms (By luke.wang.7509):

  這個(gè)解法的生成形式和上一個(gè)并無不同,不過上一個(gè)解法每一次都要從第一個(gè)丑數(shù)開始乘顯然是沒有必要的,因?yàn)橛泻芏嘀貜?fù),這里就避免了這個(gè)問題

public class Solution {
    public int nthUglyNumber(int n) {
        if(n<=0) return 0;
        int a=0,b=0,c=0;
        List<Integer> table = new ArrayList<Integer>();
        table.add(1);
        while(table.size()<n)
        {
            int next_val = Math.min(table.get(a)*2,Math.min(table.get(b)*3,table.get(c)*5));
            table.add(next_val);
            if(table.get(a)*2==next_val) a++;
            if(table.get(b)*3==next_val) b++;
            if(table.get(c)*5==next_val) c++;
        }
        return table.get(table.size()-1);
    }
}

(Java) Version 3 Time: 4ms (By TheKingRingReal):

  DFS是深度優(yōu)先的搜索算法,這里我還沒能理解,不過從結(jié)果上看,已經(jīng)很顯然了……4ms快到媽都不認(rèn)得是誰
  作者的解釋:


we can get a tree like this which contains all the ugly number ;just use three point to dfs because of I can not find the relationship between three point ; so we can think it just like this picture

each point 3 and 5 can have the 2_3and 2_5;3_5 child.and we can use a tricky in programming that if we meet 2_3=6 we should p2++;p3++;if 3
5:p5++;p3++;just like the code writ in DFS function*

public class Solution {
    public int nthUglyNumber(int n) {
            int[] dp=new int[n];dp[0]=1;
            return DFS(dp,1,0,0,0,n);
    }

    private int DFS(int[] dp, int i, int p2, int p3, int p5, int n) {
        if (i==n)return dp[n-1];
        dp[i]=Math.min(dp[p2]*2, Math.min(dp[p3]*3,dp[p5]*5));
        if (dp[i]==dp[p2]*2)p2++;
        if(dp[i]==dp[p3]*3)p3++;
        if (dp[i]==dp[p5]*5)p5++;
        return DFS(dp, i+1, p2, p3, p5, n);
    }
}

(Java) Version 4 Time: 2ms (By zmajia):

  這個(gè)哈哈哈哈哈哈逗逼把測試樣例的極限試了出來,然后打表了哈哈哈哈哈哈,實(shí)在是太壞了,所以獲得了最快的速度,已知極限用打表的方式空間換時(shí)間還是很管用的

public class Solution {
        static int[] save = new int[3000];
        static int flag = 0;
        public int nthUglyNumber(int n) {
           if(flag == 0){
               flag ++;
               init();
           }
           return save[n-1];
        }
        public static void init(){
            int _2 = 0, _3 = 0, _5 = 0;
            save[0] = 1;
            for(int i = 1; i < 3000; i++){
                int min = Math.min(save[_2]*2, Math.min(save[_3]*3,save[_5]*5));
                if(save[_2]*2 == min) {
                    save[i] = save[_2]*2;
                    _2 ++;
                }
                if(save[_3]*3 == min) {
                    save[i] = save[_3]*3;
                    _3 ++;
                }
                if(save[_5]*5 == min) {
                    save[i] = save[_5]*5;
                    _5 ++;
                }
            }
        }
    }

(Java) Version 5 Time: 108ms (By saharH):

  TreeSet我沒有怎么研究過,雖然慢但這是我看到的最簡潔的做法,其中起作用的應(yīng)該就是TreeSet的一些特性了,值得研究

public class Solution {
    public int nthUglyNumber(int n) {
        TreeSet<Long> hs = new TreeSet<>(Arrays.asList(1l, 2l, 3l, 5l));
        Long e = 1l;
        while( n != 0){
            e = hs.pollFirst();
            hs.add(e * 2);
            hs.add(e * 3);
            hs.add(e * 5);
            n--;
        }
        return e.intValue();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,890評論 0 33
  • 姐姐夏萱,天生心臟不好,一直在治療中,大哥夏柯,成熟穩(wěn)重,對妹妹很溺愛。他們的爸爸夏安,媽媽蘇晴是一對顏值很高的...
    smile竹閱讀 340評論 0 0
  • 2017年7月11日,多云,天使助殘服務(wù)團(tuán)隊(duì)于11:25接到家住西華北區(qū)6幢4單元203行動(dòng)不便的殘疾人杜玉昆電話...
    C11閱讀 221評論 0 0
  • 悵望灰天月何在, 就似君影無痕, 叫人捉摸不透, 還生明, 寂如花, 香如子, 湘妃一舞天涯, 悔之, 泣涕之, ...
    Ulia閱讀 267評論 0 13
  • 愛上一個(gè)人后有些歌會不忍聽,因?yàn)楦柙~暗含著心情,有些話不敢說,因?yàn)橹谎云Z就能勾起往事,想起以后,心里就有那種...
    木東木東閱讀 770評論 11 7

友情鏈接更多精彩內(nèi)容