返回

丑数 II ——暴力解法,动态规划

前端

丑数 II:清晰思路,稳步求解 —— 暴力解法,动态规划

丑数是一个神奇的存在,它在计算机编程、密码学等领域都有广泛应用。然而,什么是丑数?它又有什么特别的性质?本文将带领读者深入丑数的世界,探寻它的奥秘,并提供两种求解丑数的算法。

丑数的定义
丑数的定义很简单:它是一个只含有质因数2、3、5的正整数。质因数是指一个数的素因数,例如,质因数是3和5,那么丑数的最小集合就是:
{1,2,3,4,5,6,8,9,10,12,15,16}

暴力解法
找到第n个丑数最简单的方法是使用暴力解法。暴力解法的步骤如下:

  1. 从1开始计数。
  2. 检查当前数字是否为丑数。
  3. 如果是丑数,则将其添加到丑数列表中。
  4. 重复步骤2和步骤3,直到达到第n个丑数。

动态规划解法
动态规划是一种解决问题的算法,它通过将问题分解成更小的子问题来解决问题。对于丑数问题,我们可以将问题分解成更小的子问题,如:

  1. 第一个丑数是什么?
  2. 第二个丑数是什么?
  3. 第三个丑数是什么?

...

我们逐步解决这些子问题,最终得到第n个丑数。

算法实现
暴力解法

def is_ugly(n):
  """
  检查一个数字是否为丑数。

  Args:
    n: 要检查的数字。

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

  if n <= 0:
    return False

  # 检查n是否能被2、3、5整除。
  while n % 2 == 0:
    n //= 2
  while n % 3 == 0:
    n //= 3
  while n % 5 == 0:
    n //= 5

  # 如果n不能被2、3、5整除,则返回False。
  return n == 1


def get_nth_ugly_number(n):
  """
  找到第n个丑数。

  Args:
    n: 要找的丑数的序号。

  Returns:
    第n个丑数。
  """

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

  # 计数器,用于记录当前找到的丑数的序号。
  count = 1

  # 循环,直到找到第n个丑数。
  while count < n:
    # 检查下一个数字是否为丑数。
    next_number = ugly_numbers[-1] + 1
    if is_ugly(next_number):
      # 如果是丑数,则将其添加到丑数列表中。
      ugly_numbers.append(next_number)
      # 计数器加1。
      count += 1

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

动态规划解法

def get_nth_ugly_number(n):
  """
  找到第n个丑数。

  Args:
    n: 要找的丑数的序号。

  Returns:
    第n个丑数。
  """

  # 创建三个列表,分别存储以2、3、5为最小质因数的丑数。
  ugly_numbers_2 = [1]
  ugly_numbers_3 = [1]
  ugly_numbers_5 = [1]

  # 初始化三个指针,分别指向三个列表中的第一个元素。
  index_2 = 0
  index_3 = 0
  index_5 = 0

  # 循环,直到找到第n个丑数。
  while n > 0:
    # 计算三个列表中最小