动态规划之滚动数组

滚动数组

首先什么是滚动数组呢?就是将一个可能有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];
}
}

运用滚动数组的写法比普通的递推写法更节省空间优势,但是在时间复杂度上面并没有什么优势。

好的,先知道了滚动数组,我们就可以运用滚动数组解决下面的动态规划问题了。

posted @ 2022-03-12 22:51  shawchakong  阅读(1872)  评论(0编辑  收藏  举报