I 题目:
Write a program to check whether a given number is an ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5
. For example, 6, 8
are ugly while 14
is not ugly since it includes another prime factor 7
.
Note that 1
is typically treated as an ugly number.
解答:
如果某个数是丑数,那么它一定可以不断被 2 或者 3 或者 5 整除,然后除以之后的结果依然满足丑数的条件。
不断循环,直到这个数不再变化。此时如果是 1 则是丑数,否则不是。
class Solution {
public:
bool isUgly(int num) {
if(num == 1 || num == 2 || num == 3 || num == 5) return true;
int tmp = 0;
while(tmp != num)
{
tmp = num;
if(num % 2 == 0) num = num / 2;
if(num % 3 == 0) num = num / 3;
if(num % 5 == 0) num = num / 5;
}
if(tmp == 1)
return true;
else
return false;
}
};
II 题目:
Write a program to find the n
-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5
. For example,1, 2, 3, 4, 5, 6, 8, 9, 10, 12
is the sequence of the first 10
ugly numbers.
Note that 1
is typically treated as an ugly number.
查看 hint,可以知道每个出现在序列中的数,都是前面某个数乘以系数2,3或5之后的结果。
于是,记录上一次乘以2,3或5之前的那个数pos2, pos3, pos5,然后比较乘以系数之后的结果的最小值,放在这个序列。然后即时更新pos2, pos3, pos5。
这是我第一个版本的错误代码:
class Solution {
public:
int nthUglyNumber(int n) {
if(n <= 0) return 0;
int* nums = new int[n + 1]; nums[0] = 0; nums[1] = 1;
int pos2, pos3, pos5; pos2 = pos3 = pos5 = 1;
for(int i = 2; i <= n; i++) {
if(nums[pos2]*2 <= nums[pos3]*3 && nums[pos2]*2 <= nums[pos5]*5) {
nums[i] = nums[pos2]*2;
pos2 = i;
}
else if(nums[pos3]*3 <= nums[pos2]*2 && nums[pos3]*3 <= nums[pos5]*5) {
nums[i] = nums[pos3]*3;
pos3 = i;
}
else {
nums[i] = nums[pos5]*5;
pos5 = i;
}
}
return nums[n];
}
};
这个版本的错误在于:
- 更新pos2, pos3, pos5。正确的思路是:每个出现在序列中的数,都是前面某个数(不一定是平方数)乘以系数2,3或5之后的结果。每次更新为 i 只能保留序列中的数是平方数。正确的做法,应该是在上一次的位置依次后移一位,表示原有位置已经取过;
- 没有去重。会产生 1,2,3,4,5,6,6……6 = 2*3 = 3*2 重复取值;
修改之后的 AC 版本:
class Solution {
public:
int nthUglyNumber(int n) {
if(n <= 0) return 0;
int* nums = new int[n + 1]; nums[0] = 0; nums[1] = 1;
int pos2, pos3, pos5; pos2 = pos3 = pos5 = 1;
for(int i = 2; i <= n; i++) {
if(nums[pos2]*2 <= nums[pos3]*3 && nums[pos2]*2 <= nums[pos5]*5) {
nums[i] = nums[pos2]*2;
pos2 ++;
if(nums[i] % 3 == 0) pos3 ++;
if(nums[i] % 5 == 0) pos5 ++;
}
else if(nums[pos3]*3 <= nums[pos2]*2 && nums[pos3]*3 <= nums[pos5]*5) {
nums[i] = nums[pos3]*3;
pos3 ++;
if(nums[i] % 2 == 0) pos2 ++;
if(nums[i] % 5 == 0) pos5 ++;
}
else {
nums[i] = nums[pos5]*5;
pos5 ++;
if(nums[i] % 2 == 0) pos2 ++;
if(nums[i] % 3 == 0) pos3 ++;
}
}
return nums[n];
}
};
Super Ugly Number
Write a program to find the nth super ugly number.
Super ugly numbers are positive numbers whose all prime factors are in the given prime listprimes
of size k
. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32]
is the sequence of the first 12 super ugly numbers givenprimes
= [2, 7, 13, 19]
of size 4.
Note:
(1) 1
is a super ugly number for any given primes
.
(2) The given numbers in primes
are in ascending order.
(3) 0 < k
≤ 100, 0 < n
≤ 106, 0 < primes[i]
< 1000.
思路与上一题相同。不过,此时优化了一下,不需要每次取整,而是更准确的判断潜在乘积而去重:
class Solution {
public:
int nthSuperUglyNumber(int n, vector<int>& primes) {
int k = primes.size();
vector<int> pos(k, 0);
vector<int> ugly(n, INT_MAX);
ugly[0] = 1;
for(int i = 1; i< n; i++)
{
for(int j = 0; j < k; j++)
ugly[i] = (ugly[i] < ugly[pos[j]] * primes[j]) ? ugly[i] : (ugly[pos[j]] * primes[j]);
for(int j = 0; j < k; j++)
if(ugly[i] == ugly[pos[j]] * primes[j]) pos[j]++;
}
return ugly[n - 1];
}
};