返回

算法之美:动态规划题解(65)——最长递增子序列

前端

前言

在计算机科学领域,最长递增子序列(Longest Increasing Subsequence,LIS)问题是一个经典的动态规划问题。在该问题中,给定一个数字序列,要求找出其中最长的递增子序列,即一个满足顺序不改变且每个数字都比前一个数字大的子序列。

算法概述

动态规划是一种通过将问题分解成较小规模的子问题,并以自底向上的方式逐步解决这些子问题来求解复杂问题的算法范式。在解决最长递增子序列问题时,我们可以将问题分解成若干个较小的子问题,即对于每个数字,找出以该数字为结尾的最长递增子序列。

动态规划求解

为了解决最长递增子序列问题,我们可以使用一个动态规划表来记录子问题的解。动态规划表的每一行对应于输入序列的一个数字,每一列对应于以该数字为结尾的最长递增子序列的长度。

在动态规划表的初始化阶段,我们首先将所有行的第一列都设为 1,因为任何数字都可以构成一个长度为 1 的递增子序列。然后,我们遍历输入序列,对于每个数字,我们依次检查它之前的所有数字,如果当前数字比前一个数字大,则我们更新动态规划表中该数字所在行的列值为之前数字所在行的列值加 1。

代码实现

def longest_increasing_subsequence(nums):
  """
  求解最长递增子序列问题的函数。

  Args:
    nums: 输入的数字序列。

  Returns:
    最长递增子序列的长度。
  """

  # 初始化动态规划表。
  dp = [[0] * len(nums) for _ in range(len(nums))]
  for i in range(len(nums)):
    dp[i][i] = 1

  # 遍历输入序列。
  for i in range(1, len(nums)):
    for j in range(i):
      if nums[i] > nums[j]:
        dp[i][i] = max(dp[i][i], dp[j][i - 1] + 1)

  # 返回动态规划表中最后一个数字对应的列的最大值。
  return max(dp[-1])


# 测试代码。
nums = [1, 2, 3, 4, 5, 2, 3, 4, 5]
result = longest_increasing_subsequence(nums)
print(result)  # 输出: 5

复杂度分析

动态规划求解最长递增子序列问题的复杂度为 O(n^2),其中 n 是输入序列的长度。这主要是由于动态规划表中每个数字的列值都需要根据之前的所有数字来更新,因此总时间复杂度为 O(n^2)。

总结

最长递增子序列问题是一个经典的动态规划问题。通过使用动态规划,我们可以将问题分解成若干个较小的子问题,并以自底向上的方式逐步解决这些子问题来求解整个问题。动态规划求解最长递增子序列问题的复杂度为 O(n^2)。