My code:
public class Solution {
public int nthUglyNumber(int n) {
if (n <= 0)
return 0;
else if (n == 1)
return 1;
int i2 = 0;
int i3 = 0;
int i5 = 0;
int[] ugly = new int[n];
ugly[0] = 1;
for (int i = 1; i < n; i++) {
int temp = Math.min(2 * ugly[i2], Math.min(3 * ugly[i3], 5 * ugly[i5]));
if (temp == 2 * ugly[i2]) {
i2++;
}
if (temp == 3 * ugly[i3]) {
i3++;
}
if (temp == 5 * ugly[i5]) {
i5++;
}
ugly[i] = temp;
}
return ugly[n - 1];
}
public static void main(String[] args) {
Solution test = new Solution();
System.out.println(test.nthUglyNumber(7));
}
}
My test result:
這個做法不是我一開始的做法。但是這個做法速度更快更高效。我也是看了提示才寫出來的。
可以仔細看下這個網頁:
http://www.geeksforgeeks.org/ugly-numbers/
下面說下我的做法。使用一個優先級隊列。
然后1,進隊列,彈出。
然后 將彈出值temp分別 *2, 3, 5.
同時建立一個哈希表,并且判斷這幾個值在哈希表中是否存在過了,如果沒有,則插入優先級隊列。
差不多就是這么個思想。
代碼是:
import java.util.HashSet;
import java.util.PriorityQueue;
public class Solution_slow {
public int nthUglyNumber(int n) {
if (n <= 0)
return 0;
else if (n == 1)
return 1;
PriorityQueue<Long> q = new PriorityQueue<Long>();
HashSet<Long> h = new HashSet<Long>();
long[] result = new long[n];
int count = 0;
q.add((long) 1);
h.add((long) 1);
while (count < n) {
long temp = q.poll();
result[count] = temp;
count++;
if (!h.contains(temp * 2)) {
q.add(temp * 2);
h.add(temp * 2);
}
if (!h.contains(temp * 3)) {
q.add(temp * 3);
h.add(temp * 3);
}
if (!h.contains(temp * 5)) {
q.add(temp * 5);
h.add(temp * 5);
}
}
return (int) result[n - 1];
}
public static void main(String[] args) {
Solution_slow test = new Solution_slow();
System.out.println(test.nthUglyNumber(1407));
}
}
My test result:
明顯可以看出,慢了許多。
問題出在哪里呢?出在,我需要不斷地判斷,乘出來的數字是不是已經在優先級隊列里出現過了。
但是最上面的算法不需要考慮這個。
如果 2* ugly[i2] = 3 * ugly[i3]
那么,兩個if語句都會進入,i2,i3都會加1.
所以不會重復。
**
總結: DP
**
Anyway, Good luck, Richardo!
My code:
public class Solution {
public int nthUglyNumber(int n) {
if (n <= 0)
return 0;
int[] ugly = new int[n];
ugly[0] = 1;
int u2 = ugly[0] * 2;
int u3 = ugly[0] * 3;
int u5 = ugly[0] * 5;
int i2 = 0;
int i3 = 0;
int i5 = 0;
for (int i = 1; i < n; i++) {
int ug = Math.min(u2, Math.min(u3, u5));
ugly[i] = ug;
if (ug == u2) {
i2++;
u2 = ugly[i2] * 2;
}
if (ug == u3) {
i3++;
u3 = ugly[i3] * 3;
}
if (ug == u5) {
i5++;
u5 = ugly[i5] * 5;
}
}
return ugly[n - 1];
}
}
沒做出來。
主要問題在于,我也想到了用三個鏈表,但是三個鏈表各自是以什么規則生成的。我不知道。
其實三個鏈表是伴隨著 ugly[] 的擴大而擴大的。
是需要 ugly[] 數組的幫助的。
具體看上面那個鏈接把。下次做應該能做出來了。
Anyway, Good luck, Richardo!
My code:
public class Solution {
public int nthUglyNumber(int n) {
if (n <= 0) {
return 0;
}
int i2 = 0;
int i3 = 0;
int i5 = 0;
int[] ug = new int[n];
ug[0] = 1;
for (int i = 1; i < n; i++) {
int temp = Math.min(2 * ug[i2], Math.min(3 * ug[i3], 5 * ug[i5]));
if (temp == 2 * ug[i2]) {
i2++;
}
if (temp == 3 * ug[i3]) {
i3++;
}
if (temp == 5 * ug[i5]) {
i5++;
}
ug[i] = temp;
}
return ug[n - 1];
}
}
這道題目還是沒能做出來。只記得用三個鏈表。。
其實不是鏈表。
首先需要思考, ugly number 到底如何生成的。
正如上面的解釋所說。
[1,2,3,4,5,6,8,....]
*2
*3
*5
可以生成所有的ugly number
所以我們利用這個動態生成的數組,不斷地生成新的數插入進去。
那么如果保證不遺漏呢?
那么2, 3, 5必須 乘過 該ugly array 里面的所有數,從小到大。
這樣可以保證不遺漏。
但是又出現了一個問題:
會有重復情況。
所以如果 ug[i2] * 2 == ug[i3] * 3
那么, i2, i3 兩個指針都需要移動。
我一開始寫成了
if
else if
else
是錯的。
改成:
if
if
if
就AC了。
這的確也算是DP。
Anyway, Good luck, Richardo! -- 08/27/2016