標籤:
題目
醜數
設計一個演算法,找出只含素因子3,5,7 的第 k 大的數。
合格數如:3,5,7,9,15......
範例
如果k=4, 返回 9
挑戰
要求時間複雜度為O(nlogn)或者O(n)
解題
法一:直接暴力,逐次判斷一個數是不是醜數
下面只對其中的奇數判斷是否是醜數,加不加奇數都逾時。
class Solution { /** * @param k: The number k. * @return: The kth prime number as description. */ public long kthPrimeNumber(int k) { // write your code here int i = 0; int num = 3; while( i < k){ if(isUgly(num)){ i++; } num += 2; } return num - 2; } public boolean isUgly(long num){ while(num%3 == 0){ num = num/3; } while(num%5 ==0){ num = num/5; } while(num%7==0){ num = num/7; } return num==1; } };
法二:直接求醜數
參考連結
最小的連續三個醜數是:3,5,7.以後的每個醜數其因子也只能是3 5 7 那麼我們就可以看作:每個醜數可以寫成num = 3i* 5j*7k ,每個醜數也一定是其前面的醜數乘以 3 或5 或7 得到的數,這樣我們可以以3 5 7 作為醜數的基數數組,這個醜數數組中的每個數分別乘以 3, 5, 7,得到三個醜數數組,當然其中也一定會有重複的,選取不在原醜數數組中的最小的那個數,加入的醜數數組中,醜數數組的元素就增加一個。
問題是:對三個數字,如何分別找乘以3 5 7 的最小值?
假設先找乘以3 的最小值,由於原始醜數數組是有序的,則第一個不在醜數數組中的那個數字就是最小的,對於 5 7 同理,第一個不在醜數數組中的那個數就是最小的醜數,或者說是第一個大於所有醜數的那個數就是最小的醜數,這樣,我們就找到了三個醜數。最小的醜數加入的醜數數組中。
class Solution { /** * @param k: The number k. * @return: The kth prime number as description. */ public long kthPrimeNumber(int k) { // write your code here long u[] = new long[k+1]; u[0] = 1; int index = 1; int i1 = 0,i2 = 0,i3 = 0; long MIN = 0; while(index <= k){ MIN = Math.min(u[i1] * 3 ,Math.min(u[i2] * 5,u[i3] * 7)); u[index++] = MIN; i1 = 0; i2 = 0; i3 = 0; while( u[i1] *3 <= MIN){ i1++; } while(u[i2] *5 <= MIN){ i2++; } while(u[i3] *7 <= MIN){ i3++; } } return u[k]; }};Java Code
總耗時: 752 ms
但是通過上面程式中,每次都要遍曆一遍醜數數組,時間複雜度比較長,但是也竟然AC了,同時裡面重讀的數也很多。我們可以記錄中間的某個醜數的下標 ui來實現,現在其之前的數乘以3都會小于于最大的醜數,其之後的數乘以3都大於最大的醜數。5 7 同理。這樣,我們可以在原先找到的滿足最小大於醜數數組最大值的那個原始的下標來考慮。
設 3 5 7對應的下標是:i1 i2 i3 這裡的下標意思:u[i1]*2是第一個大於最大丑數數組最大值的數。i1 i2 i3 可以理解為不同步的三個指標
當 i1是三個最小丑數中的最小值,則u[i1]*3 加入到醜數數組中,u[i1]*3 就是當前醜數數組的最大值,同時i1+=1 這裡進行加1 處理,因為其i1之前的數乘以2的值一定小於u[i1]*3 ,並且這個元素已經在醜數數組u中了,u[i1 + 1] * 3 也就是第一個大於醜數數組最大值的數組。此時對於 i2 i3 不做處理。其他情況類似。
class Solution { /** * @param k: The number k. * @return: The kth prime number as description. */ public long kthPrimeNumber(int k) { // write your code here long u[] = new long[k+1]; u[0] = 1; int index = 1; int i1 = 0,i2 = 0,i3 = 0; long MIN = 0; while(index <= k){ MIN = Math.min(u[i1] * 3 ,Math.min(u[i2] * 5,u[i3] * 7)); u[index++] = MIN; if(MIN == u[i1] * 3){ i1 += 1; } if(MIN == u[i2] * 5){ i2 +=1; } if(MIN == u[i3] * 7){ i3 +=1; } } return u[k]; }};Java Code
總耗時: 1241 ms
用ArrayList
class Solution { /** * @param k: The number k. * @return: The kth prime number as description. */ public long kthPrimeNumber(int k) { // write your code here int i1 = 1; int i2 = 1; int i3 = 1; List<Long> list = new ArrayList<Long>(); list.add((long)1); while(list.size() <= k){ long u1 = list.get(i1-1) * 3; long u2 = list.get(i2-1) * 5; long u3 = list.get(i3-1) * 7; long min = Math.min(u1,Math.min(u2,u3)); if(min == u1) i1++; if(min == u2) i2++; if(min == u3) i3++; list.add(min); } return (long)list.get(k); }};Java Code
總耗時: 557 ms
class Solution: """ @param k: The number k. @return: The kth prime number as description. """ def kthPrimeNumber(self, k): # write your code here i1 = 1 i2 = 1 i3 = 1 u = [] u.append(1) while len(u) <= k: u1 = u[i1 - 1] * 3 u2 = u[i2 - 1] * 5 u3 = u[i3 - 1] * 7 minu = min(u1,min(u2,u3)) if minu == u1: i1 += 1 if minu == u2: i2 += 1 if minu == u3: i3 += 1 u.append(minu) return u[k]
Python Code
總耗時: 108 ms
輸出第10個醜數的計算過程:
[1]-------------------3 5 7[1, 3]-------------------9 5 7[1, 3, 5]-------------------9 15 7[1, 3, 5, 7]-------------------9 15 21[1, 3, 5, 7, 9]-------------------15 15 21[1, 3, 5, 7, 9, 15]-------------------21 25 21[1, 3, 5, 7, 9, 15, 21]-------------------27 25 35[1, 3, 5, 7, 9, 15, 21, 25]-------------------27 35 35[1, 3, 5, 7, 9, 15, 21, 25, 27]-------------------45 35 35[1, 3, 5, 7, 9, 15, 21, 25, 27, 35]-------------------45 45 49[1, 3, 5, 7, 9, 15, 21, 25, 27, 35, 45]-------------------45
lintcode 中等題:Ugly Numbers 醜數