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