思路
方法一:小顶堆
生成丑数的规律:如果已知丑数ugly,那么ugly * 2,ugly * 3和ugly * 5也都是丑数。
既然求第n小的丑数,可以采用最小堆来解决。每次弹出堆中最小的丑数,然后检查它分别乘以2、3和 5后的数是否生成过,如果是第一次生成,那么就放入堆中。第n个弹出的数即为第n小的丑数。
复杂度分析:
1 class Solution { 2 public: 3 int nthUglyNumber(int n) { 4 priority_queue<long long, vector<long long>, greater<long long>> minHeap; 5 unordered_set<long long> seen; 6 minHeap.push(1); 7 seen.insert(1); 8 9 int primes[3] = {2, 3, 5}; 10 long long currentUgly, newUgly; 11 for(int i = 1; i <= n; ++i) { 12 currentUgly = minHeap.top(); 13 minHeap.pop(); 14 15 for(int j = 0; j < 3; ++j) { 16 newUgly = currentUgly * primes[j]; 17 if(!seen.count(newUgly)) { 18 seen.insert(newUgly); 19 minHeap.push(newUgly); 20 } 21 } 22 23 } 24 25 return (int)currentUgly; 26 } 27 };
方法二:动态规划
复杂度分析:
时间复杂度: O(n)
空间复杂度: O(n)
1 class Solution { 2 public: 3 int nthUglyNumber(int n) { 4 int i2 = 0, i3 = 0, i5 = 0; 5 vector<int> nums(n); 6 nums[0] = 1; 7 for(int i = 1; i < n; i++) { 8 nums[i] = min(min(nums[i2] * 2, nums[i3] * 3), nums[i5] * 5); 9 if(nums[i] == nums[i2] * 2) ++i2; 10 if(nums[i] == nums[i3] * 3) ++i3; 11 if(nums[i] == nums[i5] * 5) ++i5; 12 } 13 return nums[n - 1]; 14 } 15 };