题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
思路
当前丑数乘以2或3或5就能得到下一个丑数。所以每得到一个丑数,下一次可以得到3个丑数
本题要求从小到大顺序的第index个丑数,所以每次要找到可以找到的最小丑数
第一个是1,接下来可以是1 * 2 , 1 * 3 , 1 * 5,此时最小的显然是2
接下来可以是2 * 2 , 2 * 3 , 2 * 5,此时就要把这次得到的三个4,6,10和上一次剩下的两个3,5比较大小,找出最小的,即3
接下来可以是3 * 2 , 3 * 3 , 3 * 5,…依次类推
法1:
本题可以建一个list,每次都对通过乘以某个丑数得到的三个数进行比较,找出其中最小的那个,放进list中
然后只把乘出这个数的那个上一趟丑数+1,继续向前寻找可能的丑数
最后找到n个丑数放进list里,最终返回list的最后一个元素值即可
法2:动态规划
和上面思路类似,写成动态规划的形式
实现
法1:
import java.util.ArrayList;
public class Solution {
public int GetUglyNumber_Solution(int index) {
/*当前丑数*2或*3或*5就能得到下一个丑数。每得到一个丑数,下一次可以得到3个丑数
本题要求从小到大顺序的第index个丑数,所以每次要找到可以找到的最小丑数
第一个是1,接下来可以是1*2,1*3,1*5,此时最小的显然是2
接下来可以是2*2,2*3,2*5,此时就要把这次得到的三个和上一次剩下的两个比较大小,找出最小的
*/
//思路:把每次都找出三个丑数中最小的,乘出这个最小数的上一个丑数就+1,继续向后找
if(index==0) return 0;
ArrayList<Integer> list=new ArrayList<>(); //存放找到的丑数
list.add(1); //第一个丑数是1
//定义已经找到的用来乘以2,3,5的丑数在list中的下标
int i2=0,i3=0,i5=0;
//开始寻找丑数,加入到list中,只要List长度<index就一直找,list最后一个就是第Index个丑数
while(list.size()<index){ //list长度不能等于index,会导致多循环一次
//算出已找到的丑数*相应数之后得到的新丑数的值
int m2=list.get(i2)*2;
int m3=list.get(i3)*3;
int m5=list.get(i5)*5;
//求出此时三个数中最小的(比较三个数,库函数min要使用两次)
int min=Math.min(m2,Math.min(m3,m5));
//把当前得到的最小的丑数加入list
list.add(min);
//哪个最小,就把乘出该数的丑数下标+1,使其继续向前乘出新丑数
if(min==m2) i2++;
if(min==m3) i3++;
if(min==m5) i5++;
}
//返回list最后一个元素的值(即第index个丑数)
return list.get(list.size()-1);
}
}
法2:
public class Solution {
public int GetUglyNumber_Solution(int index) {
//思路相似,写成动态规划
if(index==0) return 0;
if(index==1) return 1;
//dp[i]表示第i+1个丑数
int[] dp=new int[index];
dp[0]=1; //第一个丑数是1
//定义已经找到的用来乘以2/3/5的丑数在dp数组中的下标
int i2=0,i3=0,i5=0;
for(int i=1;i<index;i++){
dp[i]=Math.min(dp[i2]*2,Math.min(dp[i3]*3,dp[i5]*5)); //当前最小的丑数加入数组中
if(dp[i]==dp[i2]*2) i2++;
if(dp[i]==dp[i3]*3) i3++;
if(dp[i]==dp[i5]*5) i5++;
}
return dp[index-1];
}
}