直接抄星主的:
編寫一段程序來查找第 n 個超級丑數。
超級丑數是指其所有質因數都是長度為 k 的質數列表 primes 中的正整數。
示例:
# 輸入: n = 12, primes = [2,7,13,19]
# 輸出: 32
# 解釋: 給定長度為 4 的質數列表 primes = [2,7,13,19],前 12
# 個超級丑數序列為:[1,2,4,7,8,13,14,16,19,26,28,32] 。
# 說明:
# 1 是任何給定 primes 的超級丑數。
# 給定 primes 中的數字以升序排列。
# 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000 。
# 第 n 個超級丑數確保在 32 位有符整數范圍內。
# 來源:力扣(LeetCode)
# 鏈接:https://leetcode-cn.com/problems/super-ugly-number
# 著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
超級丑數題目來源:
https://leetcode-cn.com/problems/super-ugly-number/
首先理解題目,我做此題,讀題好幾遍,才完全明白超級丑數的定義。給定一個質數列表primes,如果一個數的所有質數列表是primes的子集,則這個數為超級丑數。
題目要求,在給定primes情況下,求出第n個丑數。
分析過程
先從暴力枚舉開始分析,假定primes等于[2,5,13],依次列舉出所有肯能的丑數:1, 2, 4, 8,
16, 32, ….
糟糕!因為光使用一個素數2,就能列舉出很多。幸好此題限定一個丑數的上限,在32
位有符整數范圍內(最大值為:2的31次方減1),即便如此窮舉的情況還是很多。
此題不太容易確定所有的丑數序列,完整的序列無法確定,排序也就無從談起,因此通過從小到大排序后找出第n個丑數的方法就不可行。
對于無法提前預知整個列表,或者構建出整個序列耗費時間或占用內存過大時,可以考慮使用堆,對應Python中的
heapq 模塊。
這道題使用heapq的求解思路如下:
1) 構建heapq,裝入第一個元素,即素數1;
2
移出heapq的根元素ugly,遍歷primes拿出prime,同時與prime的元素相乘,得到一個新的丑數,并裝入到heapq中。備注:Python中heapq是一個小根堆,也叫做優先級隊列,在裝入heapq中時,對象內部總會維護一個小根堆,所以每次pop時,都是當前heapq的最小值。
3
利用上述特性,當移出n個元素時,實際上相當于從已排序好的列表中找到其第n個小的元素,這不就是丑數列表排序好后,第n個丑數嗎!真是返回的結果。
需要注意,丑數裝入heapq時,不要出現重復。解決起來也很方便,使用集合set防止重復添加。
class Solution:
def nthSuperUglyNumber(self, n, primes):
import heapq
nums,ugly = [],0
s = set()
heapq.heapify(nums)
heapq.heappush(nums,1)
for _ in range(n):
ugly = heapq.heappop(nums)
for i in primes:
temp = ugly * i
if temp not in s:
s.add(temp)
heapq.heappush(nums,temp)
print(nums)
return ugly
def test_nthSuperUglyNumber():
s = Solution()
assert s.nthSuperUglyNumber(12, [2,7,13,19]) == 32