剑指 Offer 49. 丑数
个人思路
题意
准确理解:丑数是只能被2,3,5整除的数字,因此对一个数字是否是丑数,应让这个数字连续被2整除,连续被3整除,连续被5整除,若最后整除后剩下的数字是1,则说明是丑数,否则不是丑数
思路
错误思路
- 最初理解成为数字能被2或3或5整除,发现理解有误
- 而后又理解为不能被大于5的素数整除,所以使用素数打表,但无法存放大规模的素数
优化思路——空间换时间
所有的丑数都是之前的丑数的基础上乘2,乘3,乘5得到,因此将丑数保存在数组中,通过对已有丑数运算来得到其他的丑数,避免了对非丑数的计算
- 用maxUglyNum存放当前最大的丑数
生成丑数的过程:
- 对之前存储的丑数做乘2,乘3,乘5运算,找到刚刚大于maxUglyNum,得到bigger2,bigger3,bigger5,其中最小的为下一个丑数
- 用index2,index3,index5存放划分点的下标,即下标在index2之前的,乘2后都比maxUglyNum小,在idnex2之后的,乘2后比maxUglyNum大
- 每次生成一个丑数,直到找到第n个丑数
注意
- 1是丑数
个人错误思路代码
class Solution {
public:
static const int MAXN = 100005;
bool isPrime[MAXN];
//vector<bool> isPrime;
int prime[MAXN], pNum = 0;
void findPrime(){
memset(isPrime, true, sizeof(isPrime));
isPrime[0] = isPrime[1] = false;
for(int i = 2; i < MAXN; ++i){
if(isPrime[i]){
prime[pNum++] = i;
for(int j = i + i; j < MAXN; j += i){
isPrime[j] = false;
}
}
}
}
bool judge(int n){
if(n == 1){
return true;
}
for(int i = 0; i < pNum; ++i){
if(n % prime[i] == 0){
if(prime[i] > 5){
return false;
}
int another = n / prime[i];
if(isPrime[another] == true){
return false;
}
}
}
return true;
}
int nthUglyNumber(int n) {
findPrime();
int index = 1;
int cnt = 0;
while(1){
if(cnt == n){
index--;
break;
}
if(judge(index)){
cnt++;
}
index++;
}
return index;
}
};
未优化的代码——超时
class Solution {
public:
bool judge(int num){
while(num % 2 == 0){
num /= 2;
}
while(num % 3 == 0){
num /= 3;
}
while(num % 5 == 0){
num /= 5;
}
if(num == 1){
return true;
}else{
return false;
}
}
int nthUglyNumber(int n) {
int index = 1;
int cnt = 0;
while(1){
if(cnt == n){
break;
}
if(judge(index)){
cnt++;
}
if(cnt < n){
index++;
}
}
return index;
}
};
以空间换时间的优化代码
class Solution {
public:
int ugly[2000];
int nthUglyNumber(int n) {
ugly[0] = 0;
ugly[1] = 1;
int cur = 1;//当前是第几个丑数下标
int maxUglyNum = ugly[cur];//当前最大的丑数
int index2 = 0, index3 = 0, index5 = 0;//2,3,5的划分点,比index2小的,乘上2也都小于maxUglyNum
int bigger2, bigger3, bigger5;//乘2,3,5后得到的数字
if(n <= 0){
return 0;
}
while(1){
if(cur < n){
cur++;
}
else{
break;
}
while(ugly[index2] * 2 <= maxUglyNum){
index2++;
}
bigger2 = ugly[index2] * 2;
while(ugly[index3] * 3 <= maxUglyNum){
index3++;
}
bigger3 = ugly[index3] * 3;
while(ugly[index5] * 5 <= maxUglyNum){
index5++;
}
bigger5 = ugly[index5] * 5;
ugly[cur] = min(bigger2, min(bigger3, bigger5));
maxUglyNum = ugly[cur];
}
return ugly[cur];
}
};