【剑指offer】【动态规划】49.丑数
题目链接:https://leetcode-cn.com/problems/chou-shu-lcof/
常规解法
从0开始依次判断是不是丑数,判断到第n个返回; 算法直观,代码简介,但是效率不高,而且直接超时了
class Solution {
public:
bool isUgly(int n)
{
while(n % 2 == 0)
n /= 2;
while(n % 3 == 0)
n /= 3;
while(n % 5 == 0)
n /= 5;
return n == 1 ? true : false;
}
int nthUglyNumber(int n) {
int unlyNum = 0;
int number = 0;
while(unlyNum < n)
{
++number;
if(isUgly(number))
++unlyNum;
}
return number;
}
};
三路归并
- 利用丑数的定义,并且一个丑数乘以2,3,5以后仍然是一个丑数。
- 假设当前存在 3 个数组 nums2, nums3, nums5 分别代表丑数序列从 1 开始分别乘以 2, 3, 5 的序列, 即
nums2 = {1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2,...}
nums3 = {1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3,...}
nums5 = {1 * 5, 2 * 5, 3 * 5, 4 * 5, 5 * 5, 6 * 5,...}
那么, 最终的丑数序列实际上就是这 3 个有序序列对的合并结果, 计算丑数序列也就是相当于 合并 3 个有序序列。 - 合并 3 个有序序列, 每一个序列都各自维护一个指针, 然后比较指针指向的元素的值, 将最小的放入最终的合并数组中, 并将相应指针向后移动一个元素。
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> q(1, 1); // 1放入丑数集合
int i = 0, j = 0, k = 0; //i j k分别表示2,3,5三个质因子
while(--n)
{
//依次往q中插入数,将i*2,j*3,k*5中最小的放入数组;
//三路归并
int x = min(q[i] * 2, min(q[j] *3, q[k] * 5));
q.push_back(x);
//如果有重复 都要往后移动
if(q[i] * 2 == x) i++;
if(q[j] * 3 == x) j++;
if(q[k] * 5 == x) k++;
}
return q.back();
}
};
知识的价值不在于占有,而在于使用