设计一个算法,找出只含素因子2、3、5的第n小的数,符合条件的数如:1、2、3、4、5、6、8、9、10、12…
如果n=9,返回10。
def find_nth_number(n):
if n <= 0:
return None
numbers = [1]
idx2 = 0 # 索引指向最后一个乘以2的数
idx3 = 0 # 索引指向最后一个乘以3的数
idx5 = 0 # 索引指向最后一个乘以5的数
for _ in range(1, n):
next_num = min(numbers[idx2] * 2, numbers[idx3] * 3, numbers[idx5] * 5)
numbers.append(next_num)
if next_num == numbers[idx2] * 2:
idx2 += 1
if next_num == numbers[idx3] * 3:
idx3 += 1
if next_num == numbers[idx5] * 5:
idx5 += 1
return numbers[-1]
print(find_nth_number(9)) # 输出:10
print(find_nth_number(15)) # 输出:24
上述代码使用“丑数”算法(Ugly Number Algorithm)。
它的核心思想是将数字拆分成若干个质因子的乘积,而这个算法只考虑素因子 2、3、5。具体来说,该算法使用动态规划的思想,维护三个指针 idx2、idx3 和 idx5 分别表示当前已经乘以 2、3、5 的数的索引位置,然后每次取三个指针指向的数中的最小值作为下一个丑数。
具体实现步骤如下:
- 定义一个列表 numbers,用于存储已经生成的丑数,初始化为 [1]。
- 定义三个指针 idx2、idx3 和 idx5,初始值都为 0。
- 从 1 开始循环,依次生成第 2、3、4、...、n 个丑数。
- 对于当前要生成的第 i 个丑数,其值等于三个指针指向的数中的最小值,即 min(numbers[idx2] * 2, numbers[idx3] * 3, numbers[idx5] * 5)。
- 将上一步生成的数添加到列表 numbers 中。
- 如果新生成的数等于 numbers[idx2] * 2,则将指针 idx2 加 1;如果等于 numbers[idx3] * 3,则将指针 idx3 加 1;如果等于 numbers[idx5] * 5,则将指针 idx5 加 1。
- 重复步骤 4~6,直到生成第 n 个丑数为止。
- 返回列表 numbers 中的最后一个数即为第 n 小的丑数。
这种算法的时间复杂度为 ,因为每次需要生成一个新的丑数,而且每个丑数都需要比较三个指针指向的数中的最小值。