动态规划之滚动数组
滚动数组
首先什么是滚动数组呢?就是将一个可能有100元素的遍历,我用一个size=2的数组去遍历,这时你可能会问容量为3的数组大小明明小于100啊,为什么可以拿他去遍历100个元素呢?
这时我会用一句话回答你:“具体问题具体分析!”,你有没有想过,如果我遍历过的元素就再也不会使用他了,那我是不是可以将这个元素丢弃呢?
所以滚动数组常常用于解决递推问题,我在上一章就说过:“递推数组的核心思想就是数学归纳法,而数学归纳法的第二步就是通过前一个状态的运算得到当前状态”,那么假设我第十个状态的结果只要知道第九个状态的具体情况,那我还需要第一个,第二个,第三个。。。。状态的情况呢?是不是不需要了,那就可以舍弃掉了,这是滚动数组就派上用场了。
中上,如果问题的解决对于子问题的答案并不需要进行存储,那么就可以利用滚动数组的思想解决问题,更加的节省空间。
滚动数组的核心:取余
我见过的所有使用滚动数组的技巧就是取余,这样不管遍历到多大的下标值,你都可以一个小的下标值进行表示,让新的答案覆盖掉原来旧的答案。
举个例子
对于斐波那契数列F[n] = F[n - 1] + F[n - 2]有两种写法;
普通的写法:
void func1()
{
int d[101] = {0};
d[0] = 1;
d[1] = 1;
for (int i = 2; i < 100; i++)
{
d[i] = d[i - 1] + d[i - 2];
}
printf("%d", d[99]);
}
滚动数组方式的写法:
void func2()
{
int d[3];
d[0] = 1;
d[1] = 1;
for (int i = 0; i < 100; i++)
{
d[i % 3] = d[(i - 1) % 3] + d[(i - 2) % 3];
}
printf("%d", d[99 % 3]);
}
DP
对于二维数组也可以用滚动数组的方式解决:计算二维数组每一位的值等于它的上面的值和左边的值的和。
int d[100][100];
for(int i = 100;i<100;i++){
for(int j = 0;j<100;j++){
d[i][j] = d[i-1][j]+d[i][j-1];
}
}
而运用滚动数组,写法就是
int d[2][100];
for(int i = 0;i<100;i++){
for(int j = 0;j<100;j++){
d[i%2][j] = d[(i-1)%2][j]+d[i%2][j-1];
}
}
运用滚动数组的写法比普通的递推写法更节省空间优势,但是在时间复杂度上面并没有什么优势。
好的,先知道了滚动数组,我们就可以运用滚动数组解决下面的动态规划问题了。