返回

LeetCode 每日一题:丑数(No.263)的精彩解读

见解分享

题目

给定一个正整数 n,请找出第 n 个丑数。

丑数是指只包含质因数 2、3 和 5 的正整数。

示例

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。

思考

丑数的生成方式有很多种。这里我们介绍一种简单易懂的方法:

  • 从 1 开始,依次乘以 2、3 和 5,得到新的数字。
  • 将这些新数字与之前的丑数进行比较,如果它们是丑数,就将其添加到丑数列表中。
  • 重复以上步骤,直到丑数列表中包含 n 个丑数。

实现

def is_ugly(num):
  """
  判断一个数字是否为丑数。

  参数:
    num: 要判断的数字。

  返回:
    如果 num 是丑数,返回 True,否则返回 False。
  """

  # 如果 num 是 0,则它不是丑数。
  if num == 0:
    return False

  # 如果 num 可以被 2、3 或 5 整除,则它一定是丑数。
  while num % 2 == 0:
    num //= 2
  while num % 3 == 0:
    num //= 3
  while num % 5 == 0:
    num //= 5

  # 如果 num 不可以被 2、3 或 5 整除,则它不是丑数。
  return num == 1


def get_ugly_number(n):
  """
  获取第 n 个丑数。

  参数:
    n: 要获取的丑数的序号。

  返回:
    第 n 个丑数。
  """

  # 初始化丑数列表。
  ugly_numbers = [1]

  # 依次乘以 2、3 和 5,得到新的数字。
  while len(ugly_numbers) < n:
    # 计算下一个丑数的候选数字。
    candidates = [ugly_numbers[-1] * 2, ugly_numbers[-1] * 3, ugly_numbers[-1] * 5]

    # 从候选数字中选择最小的丑数。
    min_ugly_number = min(candidates)

    # 将最小的丑数添加到丑数列表中。
    ugly_numbers.append(min_ugly_number)

  # 返回第 n 个丑数。
  return ugly_numbers[n - 1]


if __name__ == "__main__":
  # 测试 is_ugly 函数。
  print(is_ugly(6))  # True
  print(is_ugly(8))  # True
  print(is_ugly(14))  # False

  # 测试 get_ugly_number 函数。
  print(get_ugly_number(10))  # 12
  print(get_ugly_number(100))  # 1536

丑数的性质

丑数具有以下性质:

  • 1 是丑数。
  • 丑数的乘积也是丑数。
  • 丑数的因子一定是 2、3 和 5。
  • 丑数的个数是无限的。

数据结构

在这道题中,我们可以使用列表来存储丑数。

动态规划

这道题也可以使用动态规划来解决。具体做法是:

  • 定义一个 dp 数组,其中 dp[i] 表示第 i 个丑数。
  • 初始化 dp 数组:dp[1] = 1。
  • 对于 i 从 2 开始到 n,计算 dp[i]:
    • 将 dp[2 * i