263 丑数
题目描述: 编写一个程序判断给定的数是否为丑数。丑数就是只包含质因数 2, 3, 5 的正整数。
思路: 此题较为简单,想要判断一个数的因子是否为2,3,5只需要判断对这个几个数进行取模然后再除以这几个数,直到最后为1即是丑数。如果对这个几个数取模都不能整除那一定不是丑数,所以使用else if,一直连续判断,如果除以2,3,5,都除不尽那就是丑数。
class Solution {
public:
bool isUgly(int num) {
if(num <= 0)
return false;
while(num % 2 == 0)
num = num / 2;
while(num % 3 == 0)
num = num / 3;
while(num % 5 == 0)
num = num / 5;
if(num == 1)
return true;
return false;
}
};
264 丑数2
题目描述: 编写一个程序,找出第 n 个丑数。丑数就是只包含质因数 2, 3, 5 的正整数。
示例: 输入: n = 10;输出: 12;解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明: 1 是丑数。n 不超过1690。
思路1(超时): 从1开始,判断每一个数是不是丑数,如果是 ,计数器加一,当计数器等于n时,返回当前的数。
思路2(优先队列)(慢): 定义一个实现小顶堆的优先队列,首先将1push进该队列,之后对每个从队列中pop出的数分别乘以2/3/5并压进队列。第n个pop出的数即为所求。
思路3(动态规划)(快): 三指针动态规划。首先创建一维动态规划数组,dp[i]表示第i个丑数的值。我们设3个指针index2、index3、index5,代表的是第几个数的2倍、第几个数3倍、第几个数5倍。动态规划方程dp[i]=min(dp[p_2]*2,dp[p_3]*3,dp[p_5]*5)
。具体思路见代码中注释。
// 思路2 优先队列
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> tmp(3,0);
tmp[0] = 2, tmp[1] = 3, tmp[2] = 5;
priority_queue <int,vector<int>,greater<int> > Q;
unordered_map<int, int> mp;
Q.push(1);
mp[1] = 1;
int cnt = 0;
int int_max = (1LL << 31) - 1;
while(!Q.empty()) {
int q = Q.top();
// cout << q << endl;
cnt++;
if(cnt == n)
return q;
Q.pop();
for(int i = 0; i < tmp.size(); i++) {
if(1LL * q * tmp[i] >= int_max)
continue;
if(mp[q * tmp[i]] == 0) {
Q.push(q * tmp[i]);
mp[q * tmp[i]] = 1;
}
}
}
return 1;
}
};
// 思路3 动态规划
class Solution {
public:
// 一维动态规划 记录index2/index3/index5。即最小的未用的乘以2的丑数的位置、乘以3的丑数的位置、乘以5的丑数位置。
int threeNumMin(int a, int b, int c) {
int tmp = min(a, b);
return min(tmp, c);
}
int nthUglyNumber(int n) {
vector<int> dp(n + 1, 0);
dp[1] = 1;
int index2 = 1, index3 = 1, index5 = 1;
for(int i = 2; i <= n; i++) {
dp[i] = threeNumMin(dp[index2] * 2, dp[index3] * 3, dp[index5] * 5);
if(dp[index2] * 2 == dp[i])
index2++;
if(dp[index3] * 3 == dp[i])
index3++;
if(dp[index5] * 5 == dp[i])
index5++;
}
return dp[n];
}
};
313 超级丑数
题目描述: 编写一段程序来查找第 n 个超级丑数。超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。
说明: 1 是任何给定 primes 的超级丑数;给定 primes 中的数字以升序排列;
0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000;第 n 个超级丑数确保在 32 位有符整数范围内。
思路: 本题目为264题(丑数2)的泛化版本 相当于将原来的index2/index3/index5封装成一个数组。动态规划或者小顶堆(耗时高)均可做。
// 动态规划解法
class Solution {
public:
// 本题目为264题(丑数2)的泛化版本 相当于将原来的index2/index3/index5封装成一个数组。
// 动态规划 或者 小顶堆(耗时高)均可做
int nthSuperUglyNumber(int n, vector<int>& primes) {
vector<int> dp(n + 1, 0);
dp[1] = 1;
vector<int> index(primes.size(), 1);
for(int i = 2; i <= n; i++) {
int minNum = INT_MAX;
for(int j = 0; j < primes.size(); j++) // 求最小值
minNum = min(minNum, dp[index[j]] * primes[j]);
for(int j = 0; j < primes.size(); j++) { // 将本次用到的素数的index加一
if(minNum == dp[index[j]] * primes[j])
index[j]++;
}
dp[i] = minNum;
}
return dp[n];
}
};