Leetcode -Ugly Number II

Leetcode -Ugly Number II_第1张图片

My code:

public class Solution {
    public int nthUglyNumber(int n) {
        if (n <= 0)
            return 0;
        else if (n == 1)
            return 1;
        int i2 = 0;
        int i3 = 0;
        int i5 = 0;
        int[] ugly = new int[n];
        ugly[0] = 1;
        for (int i = 1; i < n; i++) {
            int temp = Math.min(2 * ugly[i2], Math.min(3 * ugly[i3], 5 * ugly[i5]));
            if (temp == 2 * ugly[i2]) {
                i2++;
            }
            if (temp == 3 * ugly[i3]) {
                i3++;
            }
            if (temp == 5 * ugly[i5]) {
                i5++;
            }
            ugly[i] = temp;
        }
        return ugly[n - 1];
    }
    
    public static void main(String[] args) {
        Solution test = new Solution();
        System.out.println(test.nthUglyNumber(7));
    }
}

My test result:


Leetcode -Ugly Number II_第2张图片
Paste_Image.png

这个做法不是我一开始的做法。但是这个做法速度更快更高效。我也是看了提示才写出来的。

Leetcode -Ugly Number II_第3张图片
Paste_Image.png

可以仔细看下这个网页:
http://www.geeksforgeeks.org/ugly-numbers/

下面说下我的做法。使用一个优先级队列。
然后1,进队列,弹出。
然后 将弹出值temp分别 *2, 3, 5.
同时建立一个哈希表,并且判断这几个值在哈希表中是否存在过了,如果没有,则插入优先级队列。
差不多就是这么个思想。
代码是:

import java.util.HashSet;
import java.util.PriorityQueue;

public class Solution_slow {
    public int nthUglyNumber(int n) {
        if (n <= 0)
            return 0;
        else if (n == 1)
            return 1;
        PriorityQueue q = new PriorityQueue();
        HashSet h = new HashSet();
        long[] result = new long[n];
        int count = 0;
        q.add((long) 1);
        h.add((long) 1);
        while (count < n) {
            long temp = q.poll();
            result[count] = temp;
            count++;
            if (!h.contains(temp * 2)) {
                q.add(temp * 2);
                h.add(temp * 2);
            }
            if (!h.contains(temp * 3)) {
                q.add(temp * 3);
                h.add(temp * 3);
            }
            if (!h.contains(temp * 5)) {
                q.add(temp * 5);
                h.add(temp * 5);
            }
        }
        return (int) result[n - 1];
    }
    
    public static void main(String[] args) {
        Solution_slow test = new Solution_slow();
        System.out.println(test.nthUglyNumber(1407));
    }
}

My test result:

Leetcode -Ugly Number II_第4张图片

明显可以看出,慢了许多。
问题出在哪里呢?出在,我需要不断地判断,乘出来的数字是不是已经在优先级队列里出现过了。
但是最上面的算法不需要考虑这个。
如果 2* ugly[i2] = 3 * ugly[i3]
那么,两个if语句都会进入,i2,i3都会加1.
所以不会重复。

**
总结: DP
**

Anyway, Good luck, Richardo!

My code:

public class Solution {
    public int nthUglyNumber(int n) {
        if (n <= 0)
            return 0;

        int[] ugly = new int[n];        
        ugly[0] = 1;
        int u2 = ugly[0] * 2;
        int u3 = ugly[0] * 3;
        int u5 = ugly[0] * 5;
        int i2 = 0;
        int i3 = 0;
        int i5 = 0;
        for (int i = 1; i < n; i++) {
            int ug = Math.min(u2, Math.min(u3, u5));
            ugly[i] = ug;
            if (ug == u2) {
                i2++;
                u2 = ugly[i2] * 2;
            }
            if (ug == u3) {
                i3++;
                u3 = ugly[i3] * 3;
            }
            if (ug == u5) {
                i5++;
                u5 = ugly[i5] * 5;
            }
        }
        return ugly[n - 1];
    }
}

没做出来。
主要问题在于,我也想到了用三个链表,但是三个链表各自是以什么规则生成的。我不知道。
其实三个链表是伴随着 ugly[] 的扩大而扩大的。
是需要 ugly[] 数组的帮助的。
具体看上面那个链接把。下次做应该能做出来了。

Anyway, Good luck, Richardo!

My code:

public class Solution {
    public int nthUglyNumber(int n) {
        if (n <= 0) {
            return 0;
        }
        
        int i2 = 0;
        int i3 = 0;
        int i5 = 0;
        
        int[] ug = new int[n];
        ug[0] = 1;
        for (int i = 1; i < n; i++) {
            int temp = Math.min(2 * ug[i2], Math.min(3 * ug[i3], 5 * ug[i5]));
            if (temp == 2 * ug[i2]) {
                i2++;
            }
            if (temp == 3 * ug[i3]) {
                i3++;
            }
            if (temp == 5 * ug[i5]) {
                i5++;
            }
            ug[i] = temp;
        }
        
        return ug[n - 1];
    }
}

这道题目还是没能做出来。只记得用三个链表。。

其实不是链表。
首先需要思考, ugly number 到底如何生成的。
正如上面的解释所说。
[1,2,3,4,5,6,8,....]
*2
*3
*5
可以生成所有的ugly number
所以我们利用这个动态生成的数组,不断地生成新的数插入进去。
那么如果保证不遗漏呢?
那么2, 3, 5必须 乘过 该ugly array 里面的所有数,从小到大。
这样可以保证不遗漏。
但是又出现了一个问题:
会有重复情况。
所以如果 ug[i2] * 2 == ug[i3] * 3
那么, i2, i3 两个指针都需要移动。
我一开始写成了

if
else if
else

是错的。
改成:
if
if
if

就AC了。
这的确也算是DP。
Anyway, Good luck, Richardo! -- 08/27/2016

你可能感兴趣的:(Leetcode -Ugly Number II)