這一篇博客把ugly numbers
系列的題目作一個整理。這三道題正好是一個思路的按部就班,因此放在一篇博客當中。面試
Write a program to check whether a given number is an ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7. Note that 1 is typically treated as an ugly number.
醜數是指只包含2,3,5
質因數的數。所以6
,8
是醜數由於6=2*3
,8=2*2*2
,而14
不是醜數由於14包含質因數7。如今寫一個方法判斷一個數字是不是醜數。算法
這題只須要將全部的2,3,5質數消去以後,餘下的質數是否是1來進行判斷。代碼以下:編程
public boolean isUgly(int num) { if(num <= 0) return false; while(num % 2 == 0) num /= 2; while(num % 5 == 0) num /= 5; while(num % 3 == 0) num /= 3; return num == 1; }
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, and n does not exceed 1690.
這道題目在上一題定義的基礎上,要找到第n個醜數。數組
這題能夠使用暴力遍歷法,從1開始,對每個數都進行判斷,直到找到第n個醜數爲止。可是這樣的方法效率不好。因此須要尋找一下這些數之間的規律,從而找到更好的解決方法。微信
這裏運用了Dynamic Programming
的編程思想來解決。如今咱們能夠將醜數完整的納入如下三類:數據結構
所有醜數:1
,2
,3
,4
,5
,6
,8
...
包含醜數2:1*2
,2*2
,3*2
,4*2
,5*2
,6*2
,8*2
...
包含醜數3:1*3
,2*3
,3*3
,4*3
,5*3
,6*3
,8*3
...
包含醜數5:1*5
,2*5
,3*5
,4*5
,5*5
,6*5
,7*5
...
能夠看到,每個醜數子列上,第i
位上的值等於所有醜數的第i個醜數*素數
。咱們只須要像歸併算法中的合併方法那樣,將三個子列按照從小到大的狀況合併成一個序列便可。ide
咱們從基礎狀況開始推理,那麼每一步的結果以下;this
第0步:spa
所有醜數:1
包含醜數2:2
包含醜數3:3
包含醜數5:5
此時比較三個子序列,得出最小值爲2,則更新所有醜數序列,而且更新包含醜數2的子序列,以下:code
第1步
所有醜數:1
,2
包含醜數2:2
,4(2*2)
包含醜數3:3
,
包含醜數5:5
,
再次比較三個子序列,得出最小值爲3,更新方法同上,結果以下:
第2步
所有醜數:1
,2
,3
包含醜數2:2
,4
包含醜數3:3
,6(2*3)
包含醜數5:5
按照如上方法咱們就能夠得出第n個醜數的值。 代碼以下
public int nthUglyNumber(int n) { int idx1 = 0, idx2 = 0, idx3 = 0; int[] result = new int[n]; result[0] = 1; for(int i = 1 ; i<n ; i++){ int num1 = result[idx1] * 2; int num2 = result[idx2] * 3; int num3 = result[idx3] * 5; result[i] = Math.min(num1, Math.min(num2, num3)); if(num1==result[i]) idx1++; if(num2==result[i]) idx2++; if(num3==result[i]) idx3++; } return result[n-1]; }
Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes = [2, 7, 13, 19] of size 4. Note: (1) 1 is a super ugly number for any given primes. (2) The given numbers in primes are in ascending order. (3) 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000. (4) The nth super ugly number is guaranteed to fit in a 32-bit signed integer.
這一題和上一題的變化相比,基本素數從[2,3,5]
變成了任意數量的有序素數構成的數組。其實本質上思路仍是同樣的,咱們只須要新建一個數組來存放當前子序列醜數對應的全部醜數的下標就能夠了。代碼以下:
public int nthSuperUglyNumber(int n, int[] primes) { int[] index = new int[primes.length]; int[] uglyNumbers = new int[primes.length]; System.arraycopy(primes, 0, uglyNumbers, 0, primes.length); int[] result = new int[n]; result[0] = 1; for(int i = 1 ; i<n ; i++){ result[i] = Integer.MAX_VALUE; for(int j = 0 ; j<uglyNumbers.length ; j++){ if(uglyNumbers[j] < result[i]) result[i] = uglyNumbers[j]; } for(int j = 0 ; j <uglyNumbers.length ; j++){ if(uglyNumbers[j]==result[i]) { index[j]++; uglyNumbers[j] = primes[j] * result[index[j]]; } } } return result[n-1]; }
固然,這道題也能夠利用特殊的數據結構來完成。優先隊列能夠很好的知足該狀況。咱們先將題目中提供的全部素數輸入到優先隊列中,至關於存入了全部的子醜數列的第一個元素。所以每一個素數持有的信息包括當前對應的醜數的下標。以後咱們能夠將比較的任務交給優先隊列的完成,咱們只需從中提取最小的那個數,加到結果集中,同時別忘了更新各個子序列從而消去出現重複值的狀況。
代碼以下:
public int nthSuperUglyNumberHeap(int n, int[] primes) { int[] ugly = new int[n]; PriorityQueue<Num> pq = new PriorityQueue<>(); for (int i = 0; i < primes.length; i++) pq.add(new Num(primes[i], 1, primes[i])); ugly[0] = 1; for (int i = 1; i < n; i++) { ugly[i] = pq.peek().val; while (pq.peek().val == ugly[i]) { Num nxt = pq.poll(); pq.add(new Num(nxt.p * ugly[nxt.idx], nxt.idx + 1, nxt.p)); } } return ugly[n - 1]; } private class Num implements Comparable<Num> { int val; int idx; int p; public Num(int val, int idx, int p) { this.val = val; this.idx = idx; this.p = p; } @Override public int compareTo(Num that) { return this.val - that.val; } }
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~