1124蓝桥杯:动态规划基础(线性dp、二维dp、LIS、LCS)

一、线性DP

1.概念

DP(动态规划)全称Dynamic Programming,是运筹学的一个分支,是一种将复杂问题分解成很多重叠的子问题的解得到整个问题的解的算法。


在动态规划中有一些概念:
状态:就是形如dp[i]li] = val的取值。其中i、j为下标,也是用于描述、确定状态所需的变量,val为状态值。
状态转移:状态与状态之间的转移关系,一般可以表示为一个数学表达式,转移方向决定了迭代或递归方向。
最终状态:也就是题目所求的状态,最后的答案。

2.分析步骤

2.1.确定状态,一般为“到第i个为止,xx为j(xx为k)的方案数/最小代价/最大价值”,可以根据数据范围和复杂度来推理。
2.2.确定状态转移方程,即从已知状态得到新状态的方法,并确保按照这个方向一定可以正确地得到最终状态。
根据状态转移的方向来决定使用迭代法还是递归法(记忆化)。

2.3.确定最终状态并输出。

二、二维dp

二维dp就是指dp数组的维度为二维的dp (当然有时候可能会三维四维,或者存在一些优化使得它降成一维),广义的来讲就是有多个维度的dp,即用于描述dp状态的变量不止一个

三、最长上升子序列LIS

LIS (最长上升子序列) 是一个经典的DP模型。

子序列指的是一个序列中,按照原序列选出若干个不一定连续的元素所组成的序列。本文学O(n^2)时间复杂度的朴素LIS模型,LIS还有一种利用二分实现的O(nlogn)时间复杂度的模型,理解起来略有难度。

在求解LIS时,一般我们会设dp[i]表示1~i序列中以a[i]结尾的最长上升子序列的长度,状态转移方程为:
dp[i] = max(dp[j]+ 1), if a[i]> a[j]。

表示a[i]要插人到不同子序列后面的情况。

四、最长公共子序列LCS

LCS (Longest Common Subsequence列)是一个经典的DP模型。

本文讲解O(n^2)时间复杂度的LCS模型

LCS问题是给定两个序列A和B,求它们的最长公共子序列。

在求解LCS时,一般我们会设dp[i][i表示A[1~i]序列和B[1~j]序列中(不规定结尾)的最长公共子序的长度,状态转移方程为:

                               if a[i] =b[j]:dp[i][j]=dp[i-1][j-1]+1

                               else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

解释一下: 当a[i]=b[i]时,可以将他们作为插入到LCS的后面,使得长度变长1,当a[i]!=b[j]时,说明此时LCS不会延长,那就要从dp[i-l][j]和dp[i][j-1]中取大的作为最长的长度。

<think>嗯,用户想要了解Java中动态规划线性DP,我需要详细讲解。首先,得确定用户对动态规划的基本概念是否熟悉。可能他们知道一些,但作为讲解,还是应该从基础开始,再逐步深入。 线性DP,应该指的是问题模型是线性的,比如一维数组或者序列上的问题。常见的例子有斐波那契数列、最长递增子序列(LIS)、最长公共子序列(LCS)这些。这些例子比较典型,用户可能听说过,可以用来举例说明。 接下来,我需要明确线性DP的核心步骤:定义状态、状态转移方程、初始化和计算顺序。这部分是关键,得详细解释每个步骤的作用。比如状态定义,要说明为什么用一维数组,或者二维但有一个维度是线性变化的。 然后,可能需要举几个具体的例子。比如斐波那契数列作为入门例子,虽然简单,但能展示状态转移。然后是LIS问题,这里可以用O()的解法,说明状态转移的过程。可能还要提到更优化的O(n log n)解法,但用户可能主要关注线性DP基础,所以先讲基本的。 再考虑LCS问题,虽然是二维DP,但可以归为线性结构,因为两个序列都是线性遍历的。需要解释状态的定义和转移方程如何推导出来。 在Java代码实现部分,要给出具体的例子,比如斐波那契的迭代版本,避免递归带来的重复计算。LIS问题则需要双重循环,展示如何填充dp数组。代码要简洁,注释清晰,方便用户理解。 可能还需要总结线性DP的特点,比如状态定义通常与问题规模相关,状态转移依赖于之前的状态等。此外,注意事项部分应该包括空间优化,比如滚动数组,或者状态压缩的技巧,这对实际应用有帮助。 用户可能有疑问,如何识别问题是否适用线性DP,这里需要给出一些判断方法,比如问题是否涉及序列或数组,子问题是否可以线性分解等。同时,错误排查方面,比如初始化是否正确,边界条件是否处理妥当,这些也是常见问题。 最后,确保整个结构清晰,分点讲解,由浅入深,让用户能够逐步理解和应用。需要检查是否覆盖了线性DP的主要知识点,并且示例代码正确无误,符合Java语法规范。</think>好的!我将分步骤为您详细讲解Java中动态规划线性DP实现,结合核心原理、经典模型和代码示例。 --- ### **一、线性DP核心理解** **定义**:在一维或伪一维(如双序列)结构上,按线性顺序推导状态的动态规划。 **特点**:状态转移方程仅依赖前序有限个状态,时间复杂度通常为 $O(n)$ 或 $O(n^2)$。 --- ### **二、实现四步骤** #### **1. 定义状态** - 使用一维数组 `dp[i]`,表示以第 `i` 个元素结尾的子问题最优解 - 例:最长递增子序列中,`dp[i]` 表示以 `nums[i]` 结尾的LIS长度 #### **2. 状态转移方程** - 关键:找到 `dp[i]` 与 `dp[j] (j < i)` 的关系 - 例(LIS): $$dp[i] = \max_{0 \le j < i}(dp[j] + 1) \quad \text{当} \ nums[j] < nums[i]$$ #### **3. 初始化** - 初始状态通常为边界值,如 `dp[0] = 1` #### **4. 计算顺序** - 按线性顺序(如从左到右)填充 `dp` 数组 --- ### **三、经典模型与Java代码** #### **模型1:斐波那契数列** ```java int fib(int n) { if (n <= 1) return n; int[] dp = new int[n+1]; dp[0] = 0; dp[1] = 1; for (int i = 2; i <= n; i++) { dp[i] = dp[i-1] + dp[i-2]; // 状态转移 } return dp[n]; } ``` #### **模型2:最长递增子序列(LIS)** ```java int lengthOfLIS(int[] nums) { int[] dp = new int[nums.length]; Arrays.fill(dp, 1); int maxLen = 1; for (int i = 1; i < nums.length; i++) { for (int j = 0; j < i; j++) { if (nums[j] < nums[i]) { dp[i] = Math.max(dp[i], dp[j] + 1); } } maxLen = Math.max(maxLen, dp[i]); } return maxLen; } ``` #### **模型3:最长公共子序列(LCS)** ```java int longestCommonSubsequence(String text1, String text2) { int m = text1.length(), n = text2.length(); int[][] dp = new int[m+1][n+1]; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (text1.charAt(i-1) == text2.charAt(j-1)) { dp[i][j] = dp[i-1][j-1] + 1; } else { dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); } } } return dp[m][n]; } ``` --- ### **四、优化技巧** 1. **空间压缩**:若状态仅依赖前几个值,可用滚动数组 (例:斐波那契数列只需保存前两个状态) 2. **贪心+二分优化LIS**:时间复杂度降至 $O(n \log n)$ --- ### **五、常见问题排查** 1. **初始化错误**:检查 `dp[0]` 是否符合场景 2. **边界越界**:注意数组索引与字符串位置的偏移 3. **转移方程遗漏条件**:如LCS中字符不相等的情况 --- ### **六、适用场景判断** 当问题满足以下特征时,优先考虑线性DP: 1. 输入为序列或可线性展开的结构 2. 问题的最优解可分解为子问题的最优解 3. 子问题之间存在明显的递推关系 通过以上步骤拆解和代码实践,可以系统掌握线性DP的核心设计方法!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值