這是劍指第一次卡死個人題……記錄一下java
首先看題目:數組
把只包含質因子二、3和5的數稱做醜數(Ugly Number)。例如六、8都是醜數,但14不是,由於它包含質因子7。 習慣上咱們把1當作是第一個醜數。求按從小到大的順序的第N個醜數。ide
一開始的思路:測試
一開始,我就直接蠻力,就按照它的描述,從2到根號n一個個試,看看是否是它的因子,是的話是否是質數,是質數的話是否是2或者3或者5什麼的。spa
最後作出來,前面幾個數字都是能夠經過測試的,但提交就一直說我超時經過率爲0……而後本地測了下超時的用例1500——emmm確實是,算了半天都沒出來。指針
而後百度,百度百科上對醜數的判別:code
而後我按照這個思路,本身實現了次,也遇到了不少問題……blog
我是真正地維護了三個隊列,而後每次把最新的醜數乘以2,3,5而後分別加到三個隊列中,而後取出最小的數字處理,從哪一個隊列中取出就哪一個隊列出隊。隊列直接用PriorityQueue,能夠直接得到最小值。隊列
遇到的問題是:get
1. 我這個直接按照上面的思路作的話,到後面數字很大會溢出……而後溢出的話,好比一個很大的醜數*5溢出了,就變成一個負數而後之後的最小值就是這個負數了——個人解決方法是:重寫一個Compator,而後傳入PriorityQueue中去。
2. 這還不夠,由於到了後面,可能出現一個隊列中的全部數字都小於0的狀況,因此在拿出數字後比較出最小的這一步也要考慮到負數的狀況。
看下個人這個思路的實現的代碼,已經經過測試:
import java.util.*; public class Solution { public int GetUglyNumber_Solution(int index) { if(index <= 0)return 0; if(index == 1)return 1; Queue<Integer> q2 = new PriorityQueue<Integer>(new NewComparator()); Queue<Integer> q3 = new PriorityQueue<Integer>(new NewComparator()); Queue<Integer> q5 = new PriorityQueue<Integer>(new NewComparator()); int uglyNum = 1, count = 1, minTemp; while(true) { q2.add(uglyNum * 2); q3.add(uglyNum * 3); q5.add(uglyNum * 5); //下面的操做這麼麻煩是由於會有幾個隊列有着一樣的最小值的狀況,這時候都要讓它出隊 minTemp = getMinOfThree(q2.peek(), q3.peek(), q5.peek(), count); if(q2.peek() == minTemp)q2.poll(); if(q3.peek() == minTemp)q3.poll(); if(q5.peek() == minTemp)q5.poll(); uglyNum = minTemp; count++; if(count == index)return uglyNum; } } // 找三個數字中沒有溢出的最小值 private int getMinOfThree(int a, int b, int c, int count) { if (a < 0 || b < 0 || c < 0) {// 存在溢出狀況,有元素小於0 int[] temp = new int[3]; temp[0] = a; temp[1] = b; temp[2] = c; Arrays.sort(temp); for (int x : temp) { if (x < 0) continue; return x; } } return a < b ? (a < c ? a : c) : (b < c ? b : c); } //由於以前的那個,若是有數字溢出了,就會變成負數,負數確定最小而後就會被poll出來,最後結果就會有錯誤 private class NewComparator implements Comparator<Integer> { @Override public int compare(Integer o1, Integer o2) { // TODO Auto-generated method stub if(o1 < 0)return 1; if(o1 < o2)return -1; else if(o1 == o2)return 0; else return 1; } } }
但其實咱們能夠不用維護三個隊列:
連接:https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b
來源:牛客網
public int GetUglyNumber_Solution2(int index) { if (index <= 0) return 0; ArrayList<Integer> list = new ArrayList<Integer>(); // add進第一個醜數1 list.add(1); // 三個下標用於記錄醜數的位置 int i2 = 0, i3 = 0, i5 = 0; while (list.size() < index) { // 三個數都是可能的醜數,取最小的放進醜數數組裏面 int n2 = list.get(i2) * 2; int n3 = list.get(i3) * 3; int n5 = list.get(i5) * 5; int min = Math.min(n2, Math.min(n3, n5)); list.add(min); if (min == n2) i2++; if (min == n3) i3++; if (min == n5) i5++; } return list.get(list.size() - 1); }
能夠看見,就是三個指針在動。並且這裏彷佛不會出現溢出有負數的狀況,由於我那裏每次是用最新的醜數去乘2,3,5;而這裏是用以前的醜數,就i2,i3,i5指針所在的那個醜數來乘,因此好不少。