diff --git a/solutions/313. Super Ugly Number.md b/solutions/313. Super Ugly Number.md new file mode 100644 index 0000000..590dcab --- /dev/null +++ b/solutions/313. Super Ugly Number.md @@ -0,0 +1,70 @@ +# [313. Super Ugly Number](https://leetcode.com/problems/super-ugly-number/) +# 思路 +此题要求第n个超级丑陋的数, 与[264. Ugly Number II.md](https://leetcode.com/problems/ugly-number-ii/)是类似的, 只是这里质数可以任意给定, +加大了难度, 但本质是一样的. 大致思路就是直接从给定的质数构造ugly数, 可参见[264 题解](https://github.com/ShusenTang/LeetCode/blob/master/solutions/264.%20Ugly%20Number%20II.md). + +# 思路一 +在求k个候选值的最小值时, 可以采用直接遍历一遍的思路, 这样总的复杂度就是O(kn). +> STL中`min_element`和`max_element`可以求一个vector的最小/大值, 返回的是迭代器. + +# 思路二 +当k比较大时候思路一就显得可优化了, 我们可以维护一个大小为k的候选值最小堆, 每个元素包含两个域: value和idx, 分别代表值和由哪一个质数得来, 可以用pair实现. + +每当我们从堆顶pop出一个元素, 这个元素的value就是下一个丑陋的数(注意可能重复), 这个元素的idx就代表从哪一个质数得来, 应该将该质数的idx加一, 再向堆中插入下一个候选值. +由于向堆中插入和pop都是对数级别的, 所以总的时间复杂度就是O(nlogk). (但是实测比方法一慢, 猜想可能是由于测试样例k不是很大) + +> 注意学习`pair`以及`priority_queue`的用法. + +# C++ +## 思路一 +``` C++ +class Solution { +public: + int nthSuperUglyNumber(int n, vector<int>& primes) { + vector<int>nums(n, INT_MAX), candidate(primes.begin(), primes.end()), idx(n, 0); + nums[0] = 1; + for(int i = 1; i < n; i++){ + // nums[i] = *min_element(candidate.begin(), candidate.end()); + for(int &c: candidate) nums[i] = min(nums[i], c); + + for(int j = 0; j < primes.size(); j++) + if(candidate[j] == nums[i]) + candidate[j] = nums[++idx[j]] * primes[j]; + } + return nums.back(); + } +}; +``` + +## 思路二 +``` C++ +class Solution { +public: + int nthSuperUglyNumber(int n, vector<int>& primes) { + vector<int> nums(n, INT_MAX), idx(prime_n, 0); + nums[0] = 1; + + int prime_n = primes.size(); + // value, produce_by_which_prime + priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int,int>>> minheap; + for(int i = 0; i < prime_n; i++) + minheap.push({primes[i], i}); + + int count = 1; + while(count < n){ + pair<int, int>next = minheap.top(); + minheap.pop(); + + if(nums[count - 1] != next.first){ + nums[count] = next.first; + count++; + } // 避免重复 + + idx[next.second]++; + minheap.push({nums[idx[next.second]] * primes[next.second], next.second}); + } + return nums.back(); + } +}; +``` +