Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5.
Example:
Input: n = 10
Output: 12
Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
263题只让判断是否是丑数,而这道题是让求出第n个丑数
丑数的定义是只能被2,3,5的素因数整除
第一个丑数是1
思路:
可以保存每个丑数* 2, * 3, * 5到一个优先队列,然后取第n-1个
比如保存 1* 2, 1* 3, 1* 5,到优先队列,然后取最小的2出来,再保存2 * 2, 2 * 3, 2 * 5
因为涉及到排序,所以time complexity是O(NlogN)
这里用O(N)的方法,
用变量分别保存因子2, 3, 5的index,这个index指的是指向第几个丑数,而不是顺序的1,2,3…
因为如果是指向顺序的1,2…,就有7的倍数存在,违背了丑数的定义。
每次用第 i 个丑数分别乘2,3,5,取其中最小的作为下一个丑数,如果下一个是2的倍数,就把2的index加1,即下一次用下一个丑数来乘2,同理3和5,注意这里一定要同时更新2,3,5的index,而不是if…else,因为有相同的数存在,比如2和3的公倍数6,要跳过6就要同时更新2和3的index。
用list保存一系列丑数,最后返回第n个丑数即可。
第一个丑数是1,所以要先在结果list中存入1。
比如:
丑数 ×2 ×3 ×5
1: 2, 3, 5
2: 4, 6, 10
3: 6, 9, 15
然后是运行时间,试了一下cpp,如果声明vector是static,那么每次调用函数时就不会再重新产生丑数,运行时间是0ms,如果不声明static,testing每次调用时都会从头再产生丑数,运行时间是4ms
int nthUglyNumber(int n) {
static vector<int> nums{1};
static int i2 = 0;
static int i3 = 0;
static int i5 = 0;
while (nums.size() < n) {
const int next2 = nums[i2] * 2;
const int next3 = nums[i3] * 3;
const int next5 = nums[i5] * 5;
int next = min(next2, min(next3, next5));
//不能用if..else,因为有公倍数的存在,比如6,要同时更新几个数的index
//也不能用switch..case,因为next2, next3, next5是变量,而case中要求常数
if (next == next2) {
i2 ++;
}
if (next == next3) {
i3 ++;
}
if (next == next5) {
i5 ++;
}
nums.push_back(next);
}
return nums[n - 1];
}
java版
java的非static函数中不能用static变量
public int nthUglyNumber(int n) {
if(n <= 0) {
return -1;
}
List<Integer> uglyNums = new ArrayList<Integer>(){{add(1);}};
int ind2 = 0;
int ind3 = 0;
int ind5 = 0;
for(int i = 2; i <= n; i++) {
int next2 = 2 * uglyNums.get(ind2);
int next3 = 3 * uglyNums.get(ind3);
int next5 = 5 * uglyNums.get(ind5);
int next = Math.min(Math.min(next2, next3), next5);
//不能用if..else,因为有公倍数的存在,比如6,要同时更新几个数的index
//也不能用switch..case,因为next2, next3, next5是变量,而case中要求常数
if (next == next2) {
ind2 ++;
}
if (next == next3) {
ind3 ++;
}
if (next == next5) {
ind5 ++;
}
uglyNums.add(next);
}
return uglyNums.get(n - 1);
}