public int GetUglyNumber_Solution (int index) { // write code here if(index<=6){ return index; } int x=0 ,y=0 ,z=0; int[] res=new int[index]; res[0]=1; for(int i=1;i<index;i++){ // 1做初始化,后续按×2 3 5取最小值,命中的数角标+1 res[i]=Math.min(res[x]*2 ,Math.min(res[y]*3 ,res[z]*5)); if(res[i]==res[x]*2){ x++; } if(res[i]==res[y]*3){ y++; } if(res[i]==res[z]*5){ z++; } } return res[index-1]; }
import java.util.*; public class Solution { public int GetUglyNumber_Solution(int index) { if(index == 0) return 0; int[] prime = {2,3,5}; PriorityQueue<Long> q = new PriorityQueue<>(); Set<Long> set = new HashSet<>(); long num = 1l; q.offer(num); while(index -- > 0) { num = q.poll(); for(int p : prime) { if(!set.contains(p * num)) { set.add(p * num); q.offer(p * num); } } } return (int)num; } }
import java.util.*; public class Solution { public int GetUglyNumber_Solution(int index) { List<Integer> list1=new ArrayList<Integer>();//存储素数 List<Integer> list2=new ArrayList<Integer>();//存储丑数 int i=1; while(true){ getSubNum(i,list1,list2); if(list2.size()==index){ return list2.get(index-1); } i++; } } public void getSubNum(int num,List<Integer> list1,List<Integer> list2){ if(num==1){ list1.add(num); list2.add(num); return; } int div_num=num/2; Set<Integer> set=new HashSet<Integer>(); for(int i=1;i<=num;i++){ int tmp1=num/i; int tmp2=num%i; if(tmp2==0){ set.add(tmp1); set.add(num/i); } } if(set.size()==2){ list1.add(num); } for(int n:list1){ if(set.contains(n)&&n!=1&&n!=2&&n!=3&&n!=5){ return; } } list2.add(num); } }时间复杂度有点高,最后一个测试用例没通过
import java.util.ArrayList; public class Solution { public int GetUglyNumber_Solution(int index) { //动态规划 int[] dp=new int[index+1]; if(index==0) return 0; dp[1]=1; int p1=1,p2=1,p3=1; for (int i = 2; i <=index; i++) { int num1=dp[p1]*2,num2=dp[p2]*3,num3=dp[p3]*5; dp[i]=Math.min(num1,Math.min(num2,num3)); if(dp[i]==num1) p1++; if(dp[i]==num2) p2++; if(dp[i]==num3) p3++; } return dp[index]; } }
import java.util.*; public class Solution { public int GetUglyNumber_Solution(int index) { if (index <= 6) { return index; } HashSet<Long> set = new HashSet<>(); PriorityQueue<Long> pq = new PriorityQueue<>(); long res = 0; int[] BASES = {2, 3, 5}; set.add(1L); pq.offer(1L); for (int i = 0; i < index; i++) { res = pq.poll(); for (int j = 0; j < BASES.length; j++) { long num = res * BASES[j]; if (!set.contains(num)) { set.add(num); pq.offer(num); } } } return (int)res; } }
public class Solution { public int GetUglyNumber_Solution(int index) { // 三指针: // 边界值 if(index==0){ return 0; } // 定义数组 int arr[] = new int[index]; // 分别记录x2 x3 x5的索引位置 int i2=0; int i3=0; int i5=0; // 规定第一个为1; arr[0]=1; // 每轮循环产生一个丑数 for(int i=1;i<index;i++){ arr[i] = Math.min(arr[i2]*2, Math.min(arr[i3]*3,arr[i5]*5)); // 哪个索引对应值被选中成为下一个丑数,哪个索引就+1 if(arr[i]==arr[i2]*2) i2++; if(arr[i]==arr[i3]*3) i3++; if(arr[i]==arr[i5]*5) i5++; } return arr[index-1]; } }看了题解发现和自己最初理解的不太一样,三个指针各自只分别负责x2 x3 x5三路,走了哪路哪个指针就+1,这样保证每个丑数都会被x2 x3 x5各一次。另外注意不能用else if,因为需要排除在同一轮命中2个指针的情况,比如亲测又一轮i2指向3,i3指向2,算出来都是6,三个if分别判定可以避免记录2次6
import java.util.*; public class Solution { public int GetUglyNumber_Solution(int index) { if (index == 0){ return 0; } ArrayList<Integer> list = new ArrayList<>(); int i2 = 0, i3 = 0, i5 = 0; list.add(1); for (int i = 1; i < index; i++){ list.add(Math.min(list.get(i2)*2, Math.min(list.get(i3)*3, list.get(i5)*5))); if (list.get(i) == list.get(i2)*2) i2++; if (list.get(i) == list.get(i3)*3) i3++; if (list.get(i) == list.get(i5)*5) i5++; } return list.get(index-1); } }
/* 思路: 后面的丑数由前面的丑数*2,*3,*5的最小值来生成。 与斐波那契数列一样,都是一个一个往后面生成的。 */ public int GetUglyNumber_Solution(int index) { //第0个丑数是0,不知道为什么 if(index <= 0) return 0; /*需要额外的空间,省不掉 不记录无法得到想要的值 */ ArrayList<Integer> list = new ArrayList<>(); int i2 = 0,i3 = 0,i5 = 0; list.add(1); //自己举一个n=3的例子 while(list.size() < index){ int v2 = list.get(i2) * 2; int v3 = list.get(i3) * 3; int v5 = list.get(i5) * 5; //取最小值可以两个两个取 int minVal = Math.min(v2,Math.min(v3,v5)); list.add(minVal); //i只要与最小值相等就右移(可能会有多个进行移动) if(minVal == v2) i2++; if(minVal == v3) i3++; if(minVal == v5) i5++; } return list.get(list.size()-1); }
import java.util.*; public class Solution { public int GetUglyNumber_Solution(int index) { if(index<=0) return 0; int[] arr = new int[index]; arr[0] = 1; int loc2 = 0; int loc3 = 0; int loc5 = 0; int cur; for(int i =1;i<index;++i){ cur = arr[i-1]; while(arr[loc2]*2<=cur) loc2++; while(arr[loc3]*3<=cur) loc3++; while(arr[loc5]*5<=cur) loc5++; arr[i] = Math.min(Math.min(arr[loc2]*2,arr[loc3]*3),arr[loc5]*5); } return arr[index-1]; } }
public class Solution { public int GetUglyNumber_Solution(int index) { if(index==0)return 0; int[] res=new int[index]; int t2=0,t3=0,t5=0; res[0]=1; for(int i=1;i<index;i++){ res[i]=Math.min(Math.min(res[t2]*2,res[t3]*3),res[t5]*5); if(res[i]==res[t2]*2) t2++; if(res[i]==res[t3]*3) t3++; if(res[i]==res[t5]*5) t5++; } return res[index-1]; } }丑数的定义是1或者因子只有2 3 5,可推出丑数=丑数*丑数,假定丑数有序序列为:a1,a2,a3.......an
public class Solution { public int GetUglyNumber_Solution(int index) { if(index==0) return 0; int i2=0,i3=0,i5=0; int x2,x3,x5; int []dp=new int[index]; dp[0]=1; for(int i=1;i<index;i++){ x2=dp[i2]*2; x3=dp[i3]*3; x5=dp[i5]*5;//在上一次的基础上累乘 dp[i]=Math.min(x2,Math.min(x3,x5));//最小值为下一个丑数 if(dp[i]==x2) i2++; if(dp[i]==x3) i3++; if(dp[i]==x5) i5++; } return dp[index-1]; } }
import java.util.*; public class Solution { public int GetUglyNumber_Solution(int index) { if (index <= 1) { return index; } int a = 1, b = 1, c = 1; int[] dp = new int[index + 1]; dp[1] = 1; for (int i = 2; i <= index; i++) { int n1 = dp[a] * 2, n2 = dp[b] * 3, n3 = dp[c] * 5; dp[i] = Math.min(n1, Math.min(n2, n3)); if (dp[i] == n1) { a++; } if (dp[i] == n2) { b++; } if (dp[i] == n3) { c++; } } return dp[index]; } }
public class Solution { public int GetUglyNumber_Solution(int index) { if(index <= 0) return 0; if(index == 1) return 1; int[] ret = new int[index]; ret[0] = 1; int t2 = 0, t3 = 0, t5 = 0; for(int i = 1; i < index; i++){ ret[i] = Math.min(ret[t2]*2, Math.min(ret[t3]*3,ret[t5]*5)); if(ret[i] == ret[t2]*2) t2++; if(ret[i] == ret[t3]*3) t3++; if(ret[i] == ret[t5]*5) t5++; } return ret[index-1]; } }
import java.lang.*; //思路:一个丑数成以2/3/5,得到的还是一个丑数;有3个对列pos2/pos3/pos5,每次都取最小的数,放到数组中【小于7的数都是丑数】。 public class Solution { public int GetUglyNumber_Solution(int index) { //小于7的数都是丑数 if(index < 7){ return index; } int[] result = new int[index]; //1是第一个丑数 result[0] = 1; //有3个对列pos2/pos3/pos5,每次都取最小的数,放到数组中 int pos2=0,pos3=0,pos5=0; //因为1已经是第一个丑数了,所以这里i从1开始 for(int i=1;i<index;i++){ int a = result[pos2] * 2; int b = result[pos3] * 3; int c = result[pos5] * 5; //实现Math.min(a,b,c)的效果 result[i] = Math.min(a,Math.min(b,c)); if(result[i] == a){//为了防止重复需要三个if都能够走到 pos2++; } if(result[i] == b){//为了防止重复需要三个if都能够走到 pos3++; } if(result[i] == c){//为了防止重复需要三个if都能够走到 pos5++; } } return result[index-1]; } }
使用数组记录,依次添加下一个丑数进数组;
下一个丑数计算:用base2、base3、base5记录三个基数的数组下标,ugly2、ugly3、ugly5分别表示对应基数x2、x3、x5的结果(候选丑数),下一个丑数一定是比当前最后一个丑数大的,所以如果ugly2、ugly3、ugly5如果小于等于当前最后一个丑数,需先移动下标位置重新计算,预处理后下一个丑数即ugly2、ugly3、ugly5三个候选值中的最小值
public static int GetUglyNumber_Solution(int index){ if(index<=1){ return index; } int[] array = new int[index]; array[0]=1; int lastI=1; int base2=0,base3=0,base5=0; int ugly2=array[base2]*2,ugly3=array[base3]*3,ugly5=array[base5]*5; while (lastI<index){ int max = array[lastI-1]; while (ugly2<=max){ base2++; ugly2=array[base2]*2; } while (ugly3<=max){ base3++; ugly3=array[base3]*3; } while (ugly5<=max){ base5++; ugly5=array[base5]*5; } array[lastI]=getMin(ugly2,ugly3,ugly5); System.out.println("lastI="+lastI+",ugly="+ugly2+","+ugly3+","+ugly5+"==>"+array[lastI]); lastI++; } return array[index-1]; } public static int getMin(int a,int b,int c){ int min=a; if(min>b){ min=b; } if(min>c){ min=c; } return min; }
/* i>1,第i个丑数必定可分解为2*a或3*b或5*c的形式,必定是由2*a或3*b或5*c而来。 而a,b,c也是i前面的丑数。a前面的丑数,必定已经乘过2得到过丑数。 */ public class Solution { public int GetUglyNumber_Solution(int index) { if (index <= 0) { return 0; } int[] u = new int[index]; u[0] = 1; int p2 = 0; int p3 = 0; int p5 = 0; for (int i=1;i<index;i++) { u[i] = Math.min(u[p2]*2, Math.min(u[p3]*3, u[p5]*5)); if (u[i] == u[p2]*2) { p2++; } if (u[i] == u[p3]*3) { p3++; } if (u[i] == u[p5]*5){ p5++; } } return u[index-1]; } }
public static int GetUglyNumber_Solution(int index) { if(index == 1) return 1; int i = 2; int prime = 1; while(i <= index){ prime++; int temp = prime; while(temp != 1){ if(temp%2 == 0){ temp /= 2; }else if(temp%3 == 0){ temp /= 3; }else if(temp%5 == 0){ temp /= 5; }else{ temp = prime + 1; prime ++; } } i++; } return prime; }
看了三个答案,总结一下。。。
**
**
首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,那么我们从1开始乘以2,3,5,就得到2,3,5三个丑数,在从这三个丑数出发乘以2,3,5就得到4,6,10,6,9,15,10,15,25九个丑数,我们发现这种方*得到重复的丑数,而且我们题目要求第N个丑数,这样的方法得到的丑数也是无序的。那么我们可以维护三个队列:**
(1)丑数数组: 1
乘以2的队列:2
乘以3的队列:3
乘以5的队列:5
选择三个队列头最小的数2加入丑数数组,同时将该最小的数乘以**2,3,5放入三个队列;**
(2)丑数数组:1,2
乘以2的队列:4
乘以3的队列:3,6
乘以5的队列:5,10
选择三个队列头最小的数3加入丑数数组,同时将该最小的数乘以**2,3,5放入三个队列;**
(3)丑数数组:1,2,3
乘以2的队列:4,6
乘以3的队列:6,9
乘以5的队列:5,10,15
选择三个队列头里最小的数4加入丑数数组,同时将该最小的数乘以**2,3,5放入三个队列;**
(4)丑数数组:1,2,3,4
乘以2的队列:6,8
乘以3的队列:6,9,12
乘以5的队列:5,10,15,20
选择三个队列头里最小的数5加入丑数数组,同时将该最小的数乘以**2,3,5放入三个队列;**
(5)丑数数组:1,2,3,4,5
乘以2的队列:6,8,10,
乘以3的队列:6,9,12,15
乘以5的队列:10,15,20,25
选择三个队列头里最小的数6加入丑数数组,但我们发现,有两个队列头都为6,所以我们弹出两个队列头,同时将12,18,30放入三个队列;
……………………
疑问:
1.为什么分三个队列?
丑数数组里的数一定是有序的,因为我们是从丑数数组里的数乘以2,3,5选出的最小数,一定比以前未乘以2,3,5大,同时对于三个队列内部,按先后顺序乘以2,3,5分别放入,所以同一个队列内部也是有序的;
2.为什么比较三个队列头部最小的数放入丑数数组?
因为三个队列是有序的,所以取出三个头中最小的,等同于找到了三个队列所有数中最小的。
实现思路:
我们没有必要维护三个队列,只需要记录三个指针显示到达哪一步;“|”表示指针,arr表示丑数数组;
(1)1
|2
|3
|5
目前指针指向0,0,0,队列头arr[0] * 2 = 2, arr[0] * 3 = 3, arr[0] * 5 = 5
(2)1 2
2 |4
|3 6
|5 10
目前指针指向1,0,0,队列头arr[1] * 2 = 4, arr[0] * 3 = 3, arr[0] * 5 = 5
(3)1 2 3
2| 4 6
3 |6 9
|5 10 15
目前指针指向1,1,0,队列头arr[1] * 2 = 4, arr[1] * 3 = 6, arr[0] * 5 = 5
public int GetUglyNumber_Solution(int n) { if(n0)return 0; ArrayListInteger> list=new ArrayListInteger>(); list.add(1); int i2=0,i3=0,i5=0; while(list.size()n)//循环的条件 { int m2=list.get(i2)*2; int m3=list.get(i3)*3; int m5=list.get(i5)*5; int min=Math.min(m2,Math.min(m3,m5)); list.add(min); if(min==m2)i2++; if(min==m3)i3++; if(min==m5)i5++; } return list.get(list.size()-1); }
所有的丑数分为三种类型 2i,3i,5*i 其中 i是数组中的元素,一开始只有1
2*1 31 51
22 *31* 51 *22* 32 51 23 32 5*1 2*3 32 52 2*4 33 52 25 *33* 52 *25* 34 52 2*6 34 53 28 *35* 53 *28* 36 54