文章均爲本人技術筆記,轉載請註明出處:
[1] https://segmentfault.com/u/yzwall
[2] blog.csdn.net/j_dark/java
因子只包含2,3,5的數稱爲醜數(Ugly Number),習慣上把1當作第一個醜數面試
lintcode 517 ugly numbersegmentfault
劍指offer 面試題34 醜數數組
解法:參考劍指offer,將待判斷目標依次連續整除2,3,5,若是最後獲得1,證實該數爲醜數;優化
/** * 依次整除2,3,5判斷(2,3,5順序判斷時間最優) * http://www.lintcode.com/zh-cn/problem/ugly-number/ * 題意:判斷一個數是不是醜數 * @author yzwall */ class Solution { public boolean isUgly(int num) { if (num == 0) { return false; } if (num == 1) { return true; } while (num % 2 == 0) { num /= 2; } while (num % 3 == 0) { num /= 3; } while (num % 5 == 0) { num /= 5; } return num == 1 ? true : false; } }
lintcode 4 ugly number iies5
劍指offer 面試題34 醜數拓展.net
根據醜數定義,有推論以下:
任取一個醜數$m$,記$m2 = mtimes2$,$m3 = mtimes3$,$m5 = mtimes5$code
$m2$,$m3$和$m5$必然是醜數;blog
若是$m$爲當前第$n$個醜數,那麼$m2$, $m3$和$m5$中的最小值必然是第$n+1$個醜數;隊列
經過醜數推論,用優先隊列PriorityQueue<T>
的隊首保存當前第$n$個醜數,用哈希表HashSet<T>
保證優先隊列中沒有重複醜數;
/** * 題意:求第n個醜數 * http://www.lintcode.com/zh-cn/problem/ugly-number-ii/ * 解法1:優先隊列+HashSet求解,時間複雜度O(nlogn) * @author yzwall */ class Solution13 { public int nthUglyNumber(int n) { PriorityQueue<Long> pq = new PriorityQueue<>(n, new Comparator<Long>(){ public int compare(Long o1, Long o2) { return o1 < o2 ? -1 : 1; } }); HashSet<Long> hash = new HashSet<>(); hash.add(1L); pq.offer(1L); int[] primes = new int[]{2, 3, 5}; for (int prime : primes) { hash.add((long)prime); pq.offer((long)prime); } long min = primes[0]; for (int i = 0; i < n; i++) { // min始終爲第i+1個醜數,優先隊列提供保證 min = pq.poll(); for (int prime : primes) { if (!hash.contains(min * prime)) { hash.add(min * prime); // HashSet保證優先隊列中無重複醜數 pq.offer(min * prime); } } } return (int)min; } }
根據醜數推論,與解法2.1相比,
對於當前第$n$個醜數$m$,找到超過$m$的第一個$m2$,$m3$和$m5$,三者之間的最小者必然是第$n+1$個醜數
用數組保存生成的醜數,避免使用優先隊列和哈希表,時間複雜度優化到$O(n)$,空間複雜度仍然爲$O(n)$
代碼部分參考劍指offer 面試題34 醜數拓展
自定義醜數的定義是正整數而且全部的質數因子都在所給定的一個大小爲 k 的質數集合內。
好比指定質數集合爲 [2, 7, 13, 19]
, 那麼 [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32]
是前12個超級醜數
自定義醜數是廣義化的醜數,醜數的質數集合指定爲
[2, 3, 5]
lintcode 518 siper ugly number
醜數推論,可推廣至自定義醜數:
任取一個自定義醜數$m$,記指定質數集合爲$primes[]$, 記${m}_{i} = mtimes primes[i], i = 0,1,2,...,primes.length - 1$
${m}_{i}$必然是自定義醜數;
若是$m$爲當前第$n$個醜數,那麼${m}_{i}$中的最小值必然是第$n+1$個自定義醜數;
經過上述推論,用優先隊列PriorityQueue<T>
的隊首保存當前第$n$個自定義醜數,用哈希表HashSet<T>
保證優先隊列中沒有重複自定義醜數;
/** * 題意:求第n個自定義醜數 * http://www.lintcode.com/zh-cn/problem/super-ugly-number/ * 解法1:優先隊列+HashSet求解,時間複雜度O(nlogn),空間複雜度O(n) * @author yzwall */ class Solution { public int nthSuperUglyNumber(int n, int[] primes) { PriorityQueue<Long> pq = new PriorityQueue<>(n, new Comparator<Long>(){ public int compare(Long o1, Long o2) { return o1 < o2 ? -1 : 1; } }); HashSet<Long> hash = new HashSet<>(); hash.add(1L); pq.offer(1L); for (int prime : primes) { hash.add((long)prime); pq.offer((long)prime); } long min = primes[0]; for (int i = 0; i < n; i++) { min = pq.poll(); for (int prime : primes) { if (!hash.contains(min * prime)) { hash.add(min * prime); pq.offer(min * prime); } } } return (int)min; } }