问题链接:https://leetcode.com/problems/ugly-number/和https://leetcode.com/problems/ugly-number-ii/和https://leetcode.com/problems/super-ugly-number/
关于丑陋数,问题比较简单,问题二和三也不难,但值得研究研究。
问题一思路:比较直接没啥好说的,注意丑陋数为正数
class Solution {
public boolean isUgly(int num) {
if(num<=0)
return false;
while(num>1)
{
if(num%2==0)
{
num/=2;
}
else if(num%3==0)
{
num/=3;
}
else if(num%5==0)
{
num/=5;
}
else
return false;
}
return true;
}
}
问题二:优先队列加哈希集合,注意乘法运算溢出的问题,这里使用Long型
class Solution {
public static int nthUglyNumber(int n) {
PriorityQueue<Long> pq=new PriorityQueue<>();
HashSet<Long> set=new HashSet<>();
set.add(new Long(1));
pq.add(new Long(1));
Long ret=new Long(1);
for(int i=1;i<=n;i++)
{
ret=pq.poll();
if(set.add(ret*2))
pq.add(ret*2);
if(set.add(ret*3))
pq.add(ret*3);
if(set.add(ret*5))
pq.add(ret*5);
}
return ret.intValue();
}
}
因为使用了优先队列和集合操作,时间复杂度为O(nlogK),这个效率比较低。
当然上面的思路还可以优化一下,不需要使用集合来判重,代码如下:
public int nthUglyNumber(int n) {
if(n==1) return 1;
PriorityQueue<Long> q = new PriorityQueue();
q.add(1l);
for(long i=1; i<n; i++) {
long tmp = q.poll();
while(!q.isEmpty() && q.peek()==tmp) tmp = q.poll();
q.add(tmp*2);
q.add(tmp*3);
q.add(tmp*5);
}
return q.poll().intValue();
}
其实使用TreeSet可以实现优先队列和集合的功能:
public class Solution {
public int nthUglyNumber(int n) {
TreeSet<Long> ans = new TreeSet<>();
ans.add(1L);
for (int i = 0; i < n - 1; ++i) {
long first = ans.pollFirst();
ans.add(first * 2);
ans.add(first * 3);
ans.add(first * 5);
}
return ans.first().intValue();
}
}
有没有更简洁的思路呢?Hint中提示了动态规划的思路:
public int nthUglyNumber(int n) {
int[] res = new int[n];
res[0] = 1;
int t2 = 0, t3 = 0, t5 = 0, idx = 1;
while (idx < n) {
res[idx] = Math.min(res[t2] * 2, Math.min(res[t3] * 3, res[t5] * 5));
t2 += res[idx] == res[t2] * 2 ? 1 : 0;
t3 += res[idx] == res[t3] * 3 ? 1 : 0;
t5 += res[idx] == res[t5] * 5 ? 1 : 0;
++idx;
}
return res[n - 1];
}
时间和空间复杂度都为O(n),简直clean and concise!
问题三:问题二思路是可以应用到问题三的
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
PriorityQueue<Long> pq=new PriorityQueue<>();
HashSet<Long> set=new HashSet<>();
pq.add(1L);
Long tmp=1L;
for(int i=0;i<n;i++)
{
tmp=pq.poll();
for(int j=0;j<primes.length;j++)
{
Long a=primes[j]*tmp;
if(!set.contains(a))
{
pq.add(a);
set.add(a);
}
}
}
return tmp.intValue();
}
}