leetcode1269. 停在原地的方案数

题目

有一个长度为 arrLen 的数组,开始有一个指针在索引 0 处。

每一步操作中,你可以将指针向左或向右移动 1 步,或者停在原地(指针不能被移动到数组范围外)。

给你两个整数 steps 和 arrLen ,请你计算并返回:在恰好执行 steps 次操作以后,指针仍然指向索引 0 处的方案数。

由于答案可能会很大,请返回方案数 模 10^9 + 7 后的结果。

提示:

1 <= steps <= 500
1 <= arrLen <= 10^6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-steps/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

因为之前草草看了动态规划隐约觉的很像,但是又不熟,于是想用数学硬推,发现推不出来(微笑脸)。。简单放下思路代码吧。研究动态规划去了。

class Solution {
public:
    int numWays(int steps, int arrLen) {
        //需要满足以下条件:
        //steps = right+left+stay
        //right = left < arrLen
        //right必须出现在left之前
        int result = 1;
        for(int stay=steps;stay>=0;){
            int move = steps-stay;
            if(move == 0) {
                stay = stay-2;
                continue;
            };
            //moveop是移动可能出现的位置。
            int moveop = 1;
            for(int i=0;i<move;i++){
                moveop = moveop*(steps-i)/(i+1);
            }
            moveop = moveop%((int)pow(10,9)+7);
            //每个move可以是left或者right,right在前和left在前的概率应该是对半的(x,思路不对)
            moveop = moveop*((int)pow(2,(move/2)-1)%(int)(pow(10,9)+7));
            result = result+moveop;
            stay = stay-2;
        }
        return result;
	
    }
};

动态规划

定义 f[i][j] 代表当前剩余操作数为 i,所在位置为 j 的所有方案数。

起始位置为 0,操作次数为 step,即有初始化条件 f[step][0]=1,f[0][0] 则是我们的最终答案。

不失一般性的考虑 f[i][j]可以由哪些状态转移而来:

由「原地」操作到达当前状态,消耗一次操作,此时由状态f[i+1][j] 转移而来
由「向左」操作到达当前状态,消耗一次操作,此时由状态f[i+1][j+1] 转移而来
由「向右」操作到达当前状态,消耗一次操作,此时由状态f[i+1][j−1] 转移而来
求的是方案数,即最终的f[i][j] 为三者累加值。

同时我们发现 f[i][x] 依赖于f[i+1][y],因此我们需要按照「step 从大到小」的顺序进行转移。

同时我们根据「最终回到下标 0 位置」可以推断出,最远到达的位置为 step / 2(再远就回不来了)。将最远到达位置与数组最大下标取 minmin 即可确定维度 step的范围。

作者:AC_OIer
链接:https://leetcode-cn.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-steps/solution/gong-shui-san-xie-xiang-jie-xian-xing-dp-m9q9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复盘

class Solution {
public:
    const int MODULO = 1000000007;
    int numWays(int steps, int arrLen) {
        //定义 dp[i][j] 代表当前剩余操作数为 i,所在位置为 j 的所有方案数
        int maxColumn = min(steps/2,arrLen-1);
        vector<vector<int>> dp(steps + 1, vector<int>(maxColumn + 1));
        dp[steps][0] = 1;
        for(int i = steps-1;i>=0;i--){
            for(int j = 0;j<=maxColumn;j++){
                //加原地不动的方案
                dp[i][j] =(dp[i][j]+dp[i+1][j])%MODULO;
                //加从左边来的方案
                if(j-1>=0) dp[i][j] = (dp[i][j]+dp[i+1][j-1])%MODULO;
                //加从右边来的方案
                if(j+1<=maxColumn) dp[i][j] = (dp[i][j]+dp[i+1][j+1])%MODULO;
            }
        }
        return dp[0][0];
	
    }
};

时间复杂度:共有数量级为 step * maxstep∗max 个的状态需要被转移。复杂度为 O(step * max)O(step∗max)
空间复杂度:O(step * max)O(step∗max)

改进

后面补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值