《剑指offer—面试题49:丑数》
注明:仅个人学习笔记
————————————-方法一:注释1———————————-
/**方法一,用空间换时间
*
* 用一个数组去保存丑数,再在丑数中去找需要的第几个丑数
*
*/
public class GetUglyNumber49_2
{
public int GetUglyNumber_Solution(int index)
{
if (index <= 0)
{
return 0;
}
int[] pUglyNumbers = new int[index];
pUglyNumbers[0] = 1;
int nextUglyIndex = 1;
int index2 = 0;
int index3 = 0;
int index5 = 0;
while (nextUglyIndex < index)
{
// 生成丑数时,每次不用同一个数同时乘以2,3,5
//Min中这三个数在未插入丑数数组之前,都是大于当前丑数数组中的最大值的,因为丑数数组有序,所以我们需要这三个丑数中最小的一个作为新生成的丑数
int min = Min(pUglyNumbers[index2] * 2, pUglyNumbers[index3] * 3, pUglyNumbers[index5] * 5);
pUglyNumbers[nextUglyIndex] = min;// 这个数也同时表示当前丑数数组中的最大数
int curMax = pUglyNumbers[nextUglyIndex];//也就是offer书中所设的M
/**
* //这里不能用elseif,因为可能有两个最小值,这时都要挪动,比如3*2 = 6,到了2*3 = 6。(应该是这个意思)
*/
// 因为丑数数组中的数是有序的,由于我们是按照顺序生成的,小于或者等于curMax肯定已经在数组中了,
// 说明当前pUglyNumbers[index2]这个数已经乘过2了,并且乘以2得到的数已经在丑数数组中了,所以有index2++,该下一个数去乘以2了
while (pUglyNumbers[index2] * 2 <= curMax)
++index2;
// 说明当前pUglyNumbers[index3]这个数已经乘过3了,并且乘以3得到的数已经在丑数数组中了,所以有index3++,该下一个数去乘以3了
while (pUglyNumbers[index3] * 3 <= curMax)
++index3;
// 说明当前pUglyNumbers[index5]这个数已经乘过5了,并且乘以5得到的数已经在丑数数组中了,所以有index5++,该下一个数去乘以5了
while (pUglyNumbers[index5] * 5 <= curMax)
++index5;
++nextUglyIndex;
}
int ugly = pUglyNumbers[nextUglyIndex - 1];
return ugly;
}
// 三个数中确定最小数
private int Min(int number1, int number2, int number3)
{
int min = (number1 < number2) ? number1 : number2;
min = (min < number3) ? min : number3;
return min;
}
public static void main(String[] args)
{
GetUglyNumber49_2 u = new GetUglyNumber49_2();
int ugly = u.GetUglyNumber_Solution(1500);
System.out.println(ugly);
}
}
————————————-方法一:注释2———————————-
public class test49
{
public int getUglyNumber(int index)
{
if (index < 0)
{
return 0;
}
int[] uglyNumbers = new int[index];
uglyNumbers[0] = 1;
int nextIndex = 1;
int index2 = 0;
int index3 = 0;
int index5 = 0;
while (nextIndex < index)
{
// step1 生成丑数
int M2 = uglyNumbers[index2] * 2;
int M3 = uglyNumbers[index3] * 3;
int M5 = uglyNumbers[index5] * 5;
// step2 因为丑数数组有序,从小到大排序,所以选出生成的丑数中最小的添加到丑数数组中
int min = Min(M2, M3, M5);
uglyNumbers[nextIndex] = min;
// 同时获得此时丑数数组中的最大丑数
int curUglyMax = uglyNumbers[nextIndex];
// step3 选择由哪些数用来生成下一批丑数
// 原则是,已经生成过某个倍数的丑数的数,其生成的丑数已经添加进数组,就不再用来生成相同倍数的丑数了,改由其下一个数去生成对应倍数的丑数
// 其生成的某个倍数的丑数仍未添加进数组,那继续由该数生成对应倍数的丑数
while (uglyNumbers[index2] * 2 <= curUglyMax)
index2++;
while (uglyNumbers[index3] * 3 <= curUglyMax)
index3++;
while (uglyNumbers[index5] * 5 <= curUglyMax)
index5++;
// step4 取得添加下一个丑数的索引
nextIndex++;
}
// 最后,数组中的最后一个元素即为所求
int ugly = uglyNumbers[index - 1];
return ugly;
}
// 三个数中求最小
private int Min(int number2, int number3, int number5)
{
int min = (number2 < number3) ? number2 : number3;
min = (min < number5) ? min : number5;
return min;
}
public static void main(String[] args)
{
GetUglyNumber49_2 u = new GetUglyNumber49_2();
int ugly = u.GetUglyNumber_Solution(1500);
System.out.println(ugly);
}
}
——————————-分割线:方法二,暴力查找—————————————–
/**
* 方法二
*
* 我们把只包含因因子2、3、5的数,称为丑数
*
*/
public class GetUglyNumber49
{
public static int GetUglyNumber_Solution(int index)
{
if (index <= 0 || index > Integer.MAX_VALUE)
{
return 0;// 表示不存在
}
int number = 0;
int uglyFound = 0;
while (uglyFound < index)
{
++number;
if (isUgly(number))
{
++uglyFound;
}
}
return number;
}
private static boolean isUgly(int number)
{
while (number % 2 == 0)
{
number /= 2;
}
while (number % 3 == 0)
{
number /= 3;
}
while (number % 5 == 0)
{
number /= 5;
}
return (number == 1) ? true : false;
}
public static void main(String[] args)
{
int ugly = GetUglyNumber_Solution(1500);
System.out.println(ugly);
}
}