滚动数组优化DP空间复杂度

本文详细介绍了使用动态规划(DP)和滚动数组优化技术解决distinct-subsequences问题的方法,通过减少空间复杂度至O(N),提高了算法效率。以实例'rabbbit'和'think'为例,展示了解决过程和结果。
用DP + 滚动数组优化空间

题目: distinct-subsequences

Given a string S and a string T, count the number of distinct subsequences of T in S.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Example      

Given S = "rabbbit", T = "rabbit", return 3.


此题用二维DP解决,通常DP 时间复杂度O(N * M),空间复杂度也为O(N * M), 但是我们可以用滚动数组优化空间降低到O(N)。对于二维DP, 可以优化为一维的空间,如何优化比较tricky,如果有初始化的,需要动态初始化,因为滚动数组要重复使用该值,非常重要的一点是 这里被优化的维度必须在外层循环。

参见程序如下

共三种方式解决

<think>好的,我现在需要帮助用户理解如何使用滚动数组优化动态规划算法空间复杂度。首先,我得回顾一下滚动数组的基本概念。根据引用[1]和[2],滚动数组通过重复利用数组空间来减少存储需求,特别是在DP问题中,每次计算只需要前面几个状态的结果,所以不需要保存整个DP表。 接下来,我应该分步骤说明实现方法。用户可能需要具体的例子来理解如何应用滚动数组。比如,斐波那契数列是一个经典例子,普通DP使用O(n)空间,而滚动数组可以优化到O(1)。但根据引用中的例子,比如二维的路径问题,可能需要二维滚动数组,如引用[4]中的uniquePaths问题,原本用二维数组,优化后可以用一维数组,甚至更复杂的结构。 然后,我需要考虑不同维度的DP问题如何优化。一维情况下,可能只需要两个或三个变量,如引用[1]中的斐波那契例子。二维的话,可能需要交替使用行,如引用[2]中提到的用d[i%2][j]来代替完整的二维数组。这里可能需要详细说明取模操作如何实现滚动效果。 另外,用户可能关心实现时的注意事项,比如状态的覆盖顺序。例如,在二维滚动数组中,如果按行更新,是否需要从前往后还是从后往前,以避免覆盖还未使用的旧状态。引用[4]中的代码示例可能有用,但需要解释其优化过程。 还要提到滚动数组的优缺点,比如空间减少但可能增加代码复杂度,时间上通常没有优势,但有时可能影响缓存性能。引用[2]提到滚动数组主要为了压缩存储,时间上没有优势,这点需要强调。 最后,生成相关问题时要围绕用户的需求,可能涉及其他优化技巧,比如状态压缩,或者不同DP类型的应用,比如接龙型DP中的倒推法(引用[3])。可能的问题包括如何选择滚动数组的维度,或者如何处理更复杂的状态转移。 需要确保回答结构清晰,步骤明确,并且结合具体例子帮助理解。同时,引用相关的参考资料来支持说明,比如引用[1]和[2]中的例子,以及引用[4]中的代码实现。</think>### 动态规划滚动数组优化方法 滚动数组是动态规划中用于压缩存储空间的常用技巧,通过复用数组空间减少内存占用,特别适用于**状态转移仅依赖有限前序步骤**的情况。以下是实现方法和关键要点: --- #### **一、滚动数组核心原理** 1. **空间复用** 仅保留当前计算所需的前若干状态,丢弃历史无用数据。例如斐波那契数列$f(n)=f(n-1)+f(n-2)$只需保留最近两个值[^1]。 2. **取模操作实现滚动** 通过下标取模(如`i%2`)循环覆盖旧数据,模拟“滚动”效果[^1]。 --- #### **二、不同维度DP优化实现** ##### **1. 一维DP优化(空间O(1)→O(1))** - **经典问题**:斐波那契数列 - **普通DP**:`dp[i] = dp[i-1] + dp[i-2]`(空间O(n)) - **滚动数组优化**:仅用3个变量循环更新 ```python a, b = 1, 1 for _ in range(n-2): a, b = b, a + b ``` ##### **2. 二维DP优化(空间O(mn)→O(n))** - **经典问题**:路径计数问题(LeetCode 62) - **普通DP**:`dp[i][j] = dp[i-1][j] + dp[i][j-1]`(空间O(mn)) - **滚动数组优化**:用一维数组按行更新 ```python dp = [1] * n # 初始化首行 for i in range(1, m): for j in range(1, n): dp[j] += dp[j-1] # 当前行状态仅依赖上一行和左侧 ``` ##### **3. DP优化(如三维→二维)** - **实现方法**:交替覆盖维度,例如三维DP压缩为二维数组`dp[i%2][j][k]`[^2]。 --- #### **三、实现注意事项** 1. **覆盖顺序控制** 若状态转移依赖左侧或上方数据,需按**特定顺序更新**避免覆盖未使用的旧状态。例如路径问题中按从左到右顺序更新。 2. **初始化处理** 滚动数组的初始值需与原始DP对应,例如路径问题的首行首列初始化为1[^4]。 3. **取模优化替代方案** 可用位运算`i & 1`代替`i%2`提升效率(仅限2的幂次维度)[^1]。 --- #### **四、适用场景与局限性** | 场景类型 | 优化效果 | 示例 | |------------------------|---------------------------|-----------------------| | 状态依赖前k步 | 空间O(n)→O(k) | 斐波那契数列[^1] | | 二维路径类问题 | 空间O(mn)→O(n) | 机器人路径规划[^4] | | 接龙型DP(LIS问题等) | 结合倒推法减少维度[^3] | 最长递增子序列 | **局限性**:若需要回溯具体解(如最优路径),滚动数组会丢失历史状态,此时需用额外数组记录前驱节点[^3]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值