返回

算法题每日一练:第70 天 —— 详解最长递增子序列

前端

引言

在算法的世界中,最长递增子序列(LIS)问题是一个经典而富有挑战性的课题。它要求我们在一组数字中找到一组严格递增的数字,并且这组数字的长度尽可能长。

动态规划:分步征服

解决 LIS 问题的关键在于动态规划,这是一种将复杂问题分解成更小、更易管理的子问题的强大技术。动态规划的本质是存储子问题的解决方案,避免重复计算,从而显著提高效率。

算法步骤

以下是使用动态规划求解 LIS 问题的步骤:

  1. 初始化: 创建一个长度与输入数组相同的整数数组 dp,其中每个元素最初设置为 1。dp[i] 表示以数组中第 i 个元素结尾的最长递增子序列的长度。

  2. 递推: 对于数组中的每个元素 i:

    • 遍历之前的元素 j < i:
    • 如果 nums[i] > nums[j],则 dp[i] = max(dp[i], dp[j] + 1)
  3. 结果: 最终,dp 数组中最大的元素代表数组中最长递增子序列的长度。

示例:

考虑数组 nums = [10, 9, 2, 5, 3, 7, 101, 18]。

  • 初始化: dp = [1, 1, 1, 1, 1, 1, 1, 1]
  • 递推:
    • i = 1:dp[1] = max(dp[1], dp[0] + 1) = max(1, 1 + 1) = 2
    • i = 2:dp[2] = max(dp[2], dp[0] + 1) = max(1, 1 + 1) = 2
    • i = 3:dp[3] = max(dp[3], dp[2] + 1) = max(1, 2 + 1) = 3
    • i = 4:dp[4] = max(dp[4], dp[3] + 1) = max(1, 3 + 1) = 4
    • i = 5:dp[5] = max(dp[5], dp[4] + 1) = max(1, 4 + 1) = 5
    • i = 6:dp[6] = max(dp[6], dp[3] + 1) = max(1, 3 + 1) = 4
    • i = 7:dp[7] = max(dp[7], dp[6] + 1) = max(1, 4 + 1) = 5
  • 结果: dp[7] = 5,表示最长递增子序列的长度为 5。最长递增子序列为 [2, 3, 7, 101, 18]。

代码实现

def lis(nums):
  n = len(nums)
  dp = [1] * n
  
  for i in range(1, n):
    for j in range(i):
      if nums[i] > nums[j]:
        dp[i] = max(dp[i], dp[j] + 1)
  
  return max(dp)

结论

通过理解动态规划的强大功能,我们成功地掌握了求解最长递增子序列问题的算法。这种方法使我们能够有效地将复杂问题分解为更小的子问题,逐步求解。下次遇到算法难题时,别忘了动态规划这一宝贵的工具!