返回

外观数列通俗解法:玩转数列描述数列,攻克LeetCode第38题

前端

问题引入

大家好,今天我们来谈谈外观数列。外观数列是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的。例如,外观数列的前 5 项如下:

1
11
21
1211
111221

可以发现,外观数列中的每一项都是由相邻数字的个数构成的。例如,第二项 11 是由两个 1 构成的,第三项 21 是由一个 2 和一个 1 构成的,第四项 1211 是由一个 1、一个 2 和两个 1 构成的,第五项 111221 是由三个 1、两个 2 和一个 1 构成的。

思路分析

现在,让我们来考虑一下如何求解外观数列的第 n 项。我们可以采用递归或递推的方法来解决这个问题。

递归方法

递归方法是通过将问题分解成更小的子问题来解决问题的。在这种情况下,我们可以将求解外观数列第 n 项的问题分解成求解外观数列第 n-1 项的问题。

例如,要求解外观数列第 5 项,我们可以先求解外观数列第 4 项。外观数列第 4 项是 1211。然后,我们可以将 1211 成 “一个 1、一个 2 和两个 1”。最后,我们将 “一个 1、一个 2 和两个 1” 翻译成数字形式,得到 111221。

递推方法

递推方法是通过从初始值开始,一步一步地推导出最终结果的方法。在这种情况下,我们可以从外观数列的第一项 1 开始,然后一步一步地推导出外观数列的每一项。

例如,要推导出外观数列的第五项,我们可以先推导出外观数列的第四项。外观数列的第四项是 1211。然后,我们可以将 1211 描述成 “一个 1、一个 2 和两个 1”。最后,我们将 “一个 1、一个 2 和两个 1” 翻译成数字形式,得到 111221。

代码实现

def count_and_say(n):
  """
  计算外观数列的第 n 项。

  参数:
    n: 一个正整数。

  返回:
    外观数列的第 n 项。
  """

  # 如果 n 等于 1,则返回 1。
  if n == 1:
    return "1"

  # 否则,递归计算外观数列的第 n-1 项。
  else:
    prev = count_and_say(n-1)

    # 将外观数列的第 n-1 项描述成 “相邻数字的个数构成的字符串”。
    description = ""
    count = 1
    for i in range(1, len(prev)):
      if prev[i] == prev[i-1]:
        count += 1
      else:
        description += str(count) + prev[i-1]
        count = 1
    description += str(count) + prev[-1]

    # 将 “相邻数字的个数构成的字符串”翻译成数字形式。
    result = ""
    for i in range(0, len(description), 2):
      result += description[i] * int(description[i+1])

    return result


# 测试代码
print(count_and_say(1))  # 输出:1
print(count_and_say(2))  # 输出:11
print(count_and_say(3))  # 输出:21
print(count_and_say(4))  # 输出:1211
print(count_and_say(5))  # 输出:111221

总结

通过本文,我们学习了外观数列的定义和求解方法。我们还学习了如何使用递归或递推的方法来解决问题。希望本文对您有所帮助。