1. 程式人生 > >LeetCode--263. Ugly Number & 264. Ugly Number II

LeetCode--263. Ugly Number & 264. Ugly Number II

問題連結:https://leetcode.com/problems/ugly-number/https://leetcode.com/problems/ugly-number-ii/

關於醜陋數,問題比較簡單,問題二也不難,但值得研究研究。

問題一思路:比較直接沒啥好說的,注意醜陋數為正數

class Solution {
    
    public boolean isUgly(int num) {
        if(num<=0)
            return false;
        while(num>1)
        {
            if(num%2==0)
            {
                num/=2;
            }
            else if(num%3==0)
            {
                num/=3;
            }
            else if(num%5==0)
            {
                num/=5;
            }
            else
                return false;
        }
        return true;
    }
}

問題二:優先佇列加雜湊集合,注意乘法運算溢位的問題,這裡使用Long型

class Solution {
    public static int nthUglyNumber(int n) {

        PriorityQueue<Long> pq=new PriorityQueue<>();
        HashSet<Long> set=new HashSet<>();
        set.add(new Long(1));
        pq.add(new Long(1));
        Long ret=new Long(1);
        for(int i=1;i<=n;i++)
        {
            ret=pq.poll();
            if(set.add(ret*2))
                pq.add(ret*2);
            if(set.add(ret*3))
                pq.add(ret*3);
            if(set.add(ret*5))
                pq.add(ret*5);
        }
        return ret.intValue();
    }
}

因為使用了優先佇列和集合操作,時間複雜度為O(nlogK),這個效率比較低。

當然上面的思路還可以優化一下,不需要使用集合來判重,程式碼如下:

public int nthUglyNumber(int n) {
    if(n==1) return 1;
    PriorityQueue<Long> q = new PriorityQueue();
    q.add(1l);
    
    for(long i=1; i<n; i++) {
        long tmp = q.poll();
        while(!q.isEmpty() && q.peek()==tmp) tmp = q.poll();
        
        q.add(tmp*2);
        q.add(tmp*3);
        q.add(tmp*5);
    }
    return q.poll().intValue();
}

其實使用TreeSet可以實現優先佇列和集合的功能:

public class Solution {
    public int nthUglyNumber(int n) {
        TreeSet<Long> ans = new TreeSet<>();
        ans.add(1L);
        for (int i = 0; i < n - 1; ++i) {
            long first = ans.pollFirst();
            ans.add(first * 2);
            ans.add(first * 3);
            ans.add(first * 5);
        }
        return ans.first().intValue();
    }
}

有沒有更簡潔的思路呢?Hint中提示了動態規劃的思路:

public int nthUglyNumber(int n) {
		int[] res = new int[n];
		res[0] = 1;
		int t2 = 0, t3 = 0, t5 = 0, idx = 1;
		while (idx < n) {
			res[idx] = Math.min(res[t2] * 2, Math.min(res[t3] * 3, res[t5] * 5));
			t2 += res[idx] == res[t2] * 2 ? 1 : 0;
			t3 += res[idx] == res[t3] * 3 ? 1 : 0;
			t5 += res[idx] == res[t5] * 5 ? 1 : 0;
			++idx;
		}
		return res[n - 1];
	}

時間和空間複雜度都為O(n),簡直clean and concise!