这题其实并不容易。
观察一下其实每个丑数都是由3个list里面的最小的那个决定的。当最小的那个被选中,其对应的系数(Id)要加1。另外,有可能出现最小值同时出现在两个list(甚至3个list)里面的情况 (e.g., 5x2 and 2x5),这种情况下每个list的Id都要加1。
(1) 1x1, 1x2, 2x2, 2x2, 3x2, 3x2, 4x2, 5x2, 5x2, 5x2 …
(2) 1x1, 1x3, 1x3, 2x3, 2x3, 2x3, 3x3, 3x3, 4x3, 4x3…
(3) 1x1, 1x5, 1x5, 1x5, 1x5, 2x5, 2x5, 2x5, 2x5, 3x5…
ugly sequences [1x1, 1x2, 1x3, 2x2, 1x5, 3x2, 4x2, 3x3, 5x2, 4x3…], index starts from 0.
下面这个视频讲得不错。
https://www.youtube.com/watch?v=uLctkg4Yf8M
下面这个链接讲的也不错
https://mp.weixin.qq.com/s/XXsWwDml_zHiTEFPZtbe3g
解法1:
注意这3个list就相当于是3个虚拟的链表一样。所以思路就跟链表合并的思路差不多。关键难度在于去重。注意下面的if不能是else if。
class Solution {
public:
/**
* @param n: An integer
* @return: the nth prime number as description.
*/
int nthUglyNumber(int n) {
//the ugly number is 2^i * 3^j * 5^k,
int id2 = 0;
int id3 = 0;
int id5 = 0;
int index = 1;
vector<int> uglys;
uglys.push_back(1);
while (index < n) {
int candidate = min(min(uglys[id2] * 2, uglys[id3] * 3), uglys[id5] * 5);
if (candidate == uglys[id2] * 2) { //不能是else if
id2++;
}
if (candidate == uglys[id3] * 3) { //不能是else if
id3++;
}
if (candidate == uglys[id5] * 5) { //不能是else if
id5++;
}
uglys.push_back(candidate);
index++;
}
return uglys[n - 1];
}
};
解法2:加上去重。注意去重后下面的else if也可以用if。但else if 会快点。
class Solution {
public:
/**
* @param n: An integer
* @return: return a integer as description.
*/
int nthUglyNumber(int n) {
vector<int> ugly(n + 1, 0);
int index = 1;
ugly[1] = 1;
int index_2 = 1, index_3 = 1, index_5 = 1;
while (index <= n) {
int candidate_2 = 2 * ugly[index_2];
int candidate_3 = 3 * ugly[index_3];
int candidate_5 = 5 * ugly[index_5];
int candidate = min(candidate_2, min(candidate_3, candidate_5));
if (candidate != ugly[index]) {
if (index < n) ugly[++index] = candidate;
else break;
}
if (candidate == candidate_2) index_2++;
else if (candidate == candidate_3) index_3++; //也可以是if, 因为上面已经去重
else if (candidate == candidate_5) index_5++; //也可以是if, 因为上面已经去重
}
return ugly[n];
}
};
解法3:图方便用的minHeap。但时间复杂度应该是O(nlogn)。
class Solution {
public:
/**
* @param n: An integer
* @return: return a integer as description.
*/
int nthUglyNumber(int n) {
priority_queue<long long, vector<long long>, greater<long long>> q;
set<long long> s;
q.push(1);
s.insert(1);
int index = 0;
vector<int> uglys = {2, 3, 5};
while (!q.empty()) {
long long top = q.top();
q.pop();
index++;
if (index == n) return top;
for (int i = 0; i < uglys.size(); i++) {
long long tmp = top * uglys[i];
if (s.find(tmp) == s.end()) {
q.push(tmp);
s.insert(tmp);
}
}
}
return -1;
}
};