【Lintcode】1553. Climbing Stairs III

题目地址:

https://www.lintcode.com/problem/climbing-stairs-iii/description

有个人想位于第 0 0 0级台阶,他想走到第 n n n级台阶,给定一个正整数数组 A A A,当他位于第 i i i级台阶的时候,他可以一次走 1 ∼ A [ i ] 1\sim A[i] 1A[i]级台阶。问他走到第 n n n级台阶有多少个不同的方案。

思路是差分数组。传统的方法是,开一个数组 c c c c [ i ] c[i] c[i]表示到台阶 i i i的方案数。首先 c [ 0 ] = 1 c[0]=1 c[0]=1,表示到达 0 0 0级台阶只有一个方案(就是不走),然后遍历 A A A,每次遍历到 A [ i ] A[i] A[i]的时候,就将 c [ i + 1 : i + A [ i ] ] c[i+1:i+A[i]] c[i+1:i+A[i]]这个区间的所有数都增加 c [ i ] c[i] c[i]。最后返回 c [ n ] c[n] c[n]即可。这里注意我们要频繁对一个区间进行加法,用差分数组可以加速这个操作。整体复杂度可以降到 O ( n ) O(n) O(n)。设 d d d c c c的差分数组,即 c [ i ] = ∑ j = 0 i d [ j ] c[i]=\sum_{j=0}^{i}d[j] c[i]=j=0id[j],那么 d [ i ] = c [ i ] − c [ i − 1 ] , d [ 0 ] = c [ 0 ] d[i]=c[i]-c[i-1],d[0]=c[0] d[i]=c[i]c[i1],d[0]=c[0]。这样要将 c [ u : v ] c[u:v] c[u:v]加上 x x x,等价于将 d [ u ] d[u] d[u]变为 d [ u ] + x d[u]+x d[u]+x,将 d [ v + 1 ] d[v+1] d[v+1]变为 d [ v + 1 ] − x d[v+1]-x d[v+1]x。这样每次将区间加 x x x这个操作的复杂度就是 O ( 1 ) O(1) O(1)了。初始 c = ( 1 , 0 , 0 , . . . ) c=(1,0,0,...) c=(1,0,0,...),所以 d = ( 1 , − 1 , 0 , 0 , . . . ) d=(1,-1,0,0,...) d=(1,1,0,0,...)。代码如下:

public class Solution {
    /**
     * @param n:   the number of steps
     * @param num: the maximum step Ming can run up at the ith step
     * @return: Return the number of ways to run up the stairs
     */
    public long Solve(int n, int[] num) {
        // Write your code here
        // c的长度实际上是n + 1,所以差分数组d的长度也是n + 1
        long[] diff = new long[n + 1];
        long MOD = (long) 1E9 + 7;
        // 初始化一下d数组
        diff[0] = 1;
        diff[1] = -1;
        
        // res维护的是c[i]
        long res = 0;
        for (int i = 0; i < n; i++) {
            res = (res + diff[i]) % MOD;
            
            // 算一下要增加的区间
            int l = i + 1, r = Math.min(n, i + num[i]);
            if (l < diff.length) {
                diff[l] = (diff[l] + res) % MOD;
            }
            if (r + 1 < diff.length) {
                diff[r + 1] = (diff[r + 1] - res) % MOD;
            }
        }
        
        // 算c[n]的时候最后要将d[n]加上去
        res = (res + diff[n]) % MOD;
        
        return res;
    }
}

时空复杂度 O ( n ) O(n) O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值