《LeetCode之每日一题》:30.停在原地的方案数

Posted 是七喜呀!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:30.停在原地的方案数相关的知识,希望对你有一定的参考价值。

停在原地的方案数


题目链接: 停在原地的方案数

有关题目

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

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

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

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

输入:steps = 3, arrLen = 2
输出:4
解释:3 步后,总共有 4 种不同的方法可以停在索引 0 处。
向右,向左,不动
不动,向右,向左
向右,不动,向左
不动,不动,不动
示例  2:

输入:steps = 2, arrLen = 4
输出:2
解释:2 步后,总共有 2 种不同的方法可以停在索引 0 处。
向右,向左
不动,不动
示例 3:

输入:steps = 4, arrLen = 2
输出:8
提示:

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

题解

1、动态规划

思路:
1.定义数组含义:
用dp[i][j]表示在 i 步操作之后,指针位于下标 j 的方案数。其中,i 的取值范围[0,steps],j的取值范围[0,arrLen - 1]
2.找出状态转移方程
由于每走一步操作后,指针指针有三种移动方式,向左,向右,或者不动,所以
dp[i][j] = dp[i - 1][j - 1] + dp[i-1][j] + dp[i - 1][j + 1]
3.找出初始值
未进行任何操作时,指针一定停留在原位,故dp[0][0] = 1;
class Solution {
public:
    const int MODULO = 1000000007;
    int numWays(int steps, int arrLen) {
        int MaxCol = min(steps,arrLen - 1);
        vector<vector<int>> dp(steps + 1,vector<int>(MaxCol + 1));
        dp[0][0] = 1;
        for (int i = 1; i <= steps; i++)//移动步数
        {

            for (int j = 0; j <= MaxCol; j++)//所位于下标
            {
                dp[i][j] = dp[i - 1][j];
                if (j - 1 >= 0)//控制左边界
                    dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % MODULO;
                if (j <= MaxCol - 1)//控制右边界
                    dp[i][j] = (dp[i][j] + dp[i - 1][j + 1]) % MODULO;
            }
        }
        return dp[steps][0];
    }
};

时间复杂度:O(steps * min(steps,arrLen - 1))
空间复杂度:O(steps * min(steps,arrLen - 1))

2、优化动态规划

结合题目,根据数学知识,移动几步后,要想归0,移动步数i必须<=steps / 2 

3、滚动数组
注意点
在这里插入图片描述

class Solution {
public:
    const int MODULO = 1000000007;
    int numWays(int steps, int arrLen) {
        int MaxCol = min(steps / 2,arrLen - 1);
        //我们对着边进行了上面2中所提到的优化
        vector<int> dp(MaxCol + 1);
        dp[0]= 1;
        for (int i = 1; i <= steps; i++)
        {
            vector<int> dpNext(MaxCol + 1);
            for (int j = 0; j <= MaxCol; j++)
            {
                dpNext[j] = dp[j];//对应原二维数组中的dp[i - 1][j]
                if (j - 1 >= 0)
                    dpNext[j] = (dpNext[j] + dp[j - 1]) % MODULO;//这个dp[j] 对应原数组中的dp[i][j]
                if (j <= MaxCol - 1)
                    dpNext[j] = (dpNext[j] + dp[j + 1]) % MODULO;
            }
            dp = dpNext;
        }
        return dp[0];
    }
};

时间复杂度:O(steps * min(steps / 2,arrLen - 1))
空间复杂度:O(min(steps / 2,arrLen - 1))
在这里插入图片描述

以上是关于《LeetCode之每日一题》:30.停在原地的方案数的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode1269. 停在原地的方案数 / 剑指 Offer 38. 字符串的排列 / 216. 组合总和 III / 剑指 Offer 39. 数组中出现次数超过一半的数字/229. 求众数(

《LeetCode之每日一题》:126.旋转图像

《LeetCode之每日一题》:117.颜色分类

《LeetCode之每日一题》:17. 旋转数组

《LeetCode之每日一题》:83.下一个排列

《LeetCode之每日一题》:129.反转字符串