滚动数组

1.滚动数组是什么?

    一个及其小巧的思维,数据结构都算不上,不过非常适用于某些问题节约空间.其实就是一个长度为2的循环队列的概念.

2.滚动数组有什么用?

    在处理一些问题特别是DP这类问题时经常需要递推,用数组记录数据是必不可少的,然而n过大时开n*n的数组会爆栈,而滚动数组可以将空间缩为2*n.

    可处理的问题多表现为多步的数据递推,而且每一步递推只会用到上一次递推的数据,此时就记得要用滚动数组优化空间.

3.滚动数组实现思路

    正是因为每一步的递推只会用到上一步的数据,故而我们只需要2*n的空间就好了,一个n保存上次递推的数据,一个n保存本次递推的数据,本次递推完之后,本次递推自然就变成了下一次递推的上次递推,故而就是滚动的在利用这两个n的空间保存要用到的数据,不会用到的数据被我们在滚动的过程中覆盖了.

   其实这个滚动数组只是常见的是长度2,长度无论为多少实际上都可以实现滚动!这里读者自己看懂了为2的在理解.

4.模版代码

const int len=2;  //一般问题用到的长度都是2 
const int maxn=100005;
int dp[maxn][len]; 
void solve(){
	
	int now=0; //上层数据是二次下标为now的dp 
	for(int i=0;i<n;i++){
		//这里通过dp[][now]的数据推出dp[][(now+1)%len]的数据 
		
		now=(now+1)%len; //滚动起来 
	}
	
}

5.基于某些问题

(1).斐波那契问题

     斐波那契知道吧?f[1]=1,f[2]=1...f[n]=f[n-1]+f[n-2],现在我问你f[100000000]是多少,答案太大取模1000000007;

 

     问题是我自己编造的,无来源,不过很经典,按照老式的数组递推肯定不行,爆栈.故而我们用长度3的滚动数组试试.

#include <stdio.h> 
typedef long long ll; 

const int len=3;  //一般问题用到的长度都是2,不过斐波那契明显是3
const ll mod=1000000007;
ll dp[len]; 
ll solve(int t){
	dp[1]=1; 
	dp[2]=1; 
	
	int now=1; //滚动的就是这个下标now 
	for(int i=3;i<=t;i++){
		//这里通过dp[now]与dp[now+1]的数据推出dp[now+2]的数据,实际代码注意求余 
		dp[(now+2)%len]=(dp[now]+dp[(now+1)%len])%mod; //斐波那契的递推 
		
		now=(now+2)%len; //滚动起来 
	}
	return dp[now]; 
}

int main(){
	printf("%lld\n",solve(100000000));//其实这里并没有体现多少优化,只是斐波那契是典型的递推,而且只会使用到前两个数据,体会一下意思就好了 
	return 0;
}

(2).待加入高难度问题.....

### 滚动数组与压缩数组的概念及用法 #### 概念定义 滚动数组是一种优化技术,主要用于动态规划问题中降低空间复杂度。其核心思想是利用状态转移方程的特点,仅保留计算当前状态所需的部分历史状态,从而避免存储整个多维数组[^1]。 相比之下,压缩数组则是通过对原始数据进行某种形式的转换或编码,减少存储需求的技术。这种技术通常依赖于数据本身的特性(如连续性、重复性),并通过特定算法实现更高效的表示方式[^4]。 --- #### 实现方式对比 ##### **滚动数组** 滚动数组的核心在于通过调整遍历顺序和更新策略,使得一维数组可以替代传统的二维 dp 数组。以下是其实现的关键点: - 遍历顺序:当使用一维 `dp` 数组时,为了防止覆盖未使用的旧值,需采用倒序遍历的方式处理背包容量[^2]。 - 更新逻辑:每次迭代只涉及有限数量的状态变量,因此可以用较小的空间保存必要的中间结果。 下面是一个基于 C++ 的简单例子展示如何运用滚动数组求解斐波那契数列: ```cpp #include <iostream> using namespace std; int main() { int a[3]; a[0] = 1; a[1] = 1; for (int i = 1; i <= 35; ++i) { // 计算第36项Fibonacci数值 a[2] = a[0] + a[1]; // 新状态由前两个状态决定 a[0] = a[1]; // 移动指针保持最新三个状态即可 a[1] = a[2]; } cout << a[2] << endl; return 0; } ``` 此代码片段展示了如何借助少量固定大小的缓冲区完成原本可能需要线性增长内存的任务[^3]。 --- ##### **压缩数组** 压缩数组则更多关注于原始输入数据结构本身是否存在冗余或者模式可被挖掘出来加以简化表达。例如,在面对一系列接近均匀分布的数据集合时,我们可以记录初始基准值加上后续变化量构成的新序列作为代替方案;这样既节省了绝对位置信息又不失原意。 具体操作如下所示: 假设有一系列整型数字 `{8, 19, 26, 39, 41, 47, 62, 74}` ,如果直接储存每条独立记录的话总共占用约 \(4 \times 9 = 36\) 字节资源。然而注意到相邻成员之间差距不大这一事实之后便能设计更加紧凑的形式——即先指定起始参照物再列举其余各步增减幅度形成最终产物 `[85103], [8, 19, 26, 39, 41, 47, 62, 74]`. 这种方法尤其适合那些具有较强规律性的大数据集场合下应用实践当中去探索发现潜在价值所在之处。 --- #### 使用场景区别 | 特性/类别 | 滚动数组 | 压缩数组 | |-------------------|---------------------------------------------|--------------------------------------------| | 主要目标 | 减少 DP 中间过程中的临时存储开销 | 缩短长期存档文件长度 | | 数据特征要求 | 不改变原有业务语义下的局部最优子结构性质 | 存在明显趋势或周期特性的大规模静态资料库 | | 技术难度等级 | 较易理解并实施 | 对领域专业知识有一定门槛 | 综上所述可以看出两者虽然都致力于提升效率但是侧重点完全不同而且适用范围也互有侧重所以应该根据实际情况灵活选用合适的方法论来进行开发工作之中. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值