LeetCode Everyday - 恰好移动 k 步到达某一位置的方法数目

76 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情

恰好移动 k 步到达某一位置的方法数目

给你两个 正 整数 startPos 和 endPos 。最初,你站在 无限 数轴上位置 startPos 处。在一步移动中,你可以向左或者向右移动一个位置。

给你一个正整数 k ,返回从 startPos 出发、恰好 移动 k 步并到达 endPos 的 不同 方法数目。由于答案可能会很大,返回对 109 + 7 取余 的结果。

如果所执行移动的顺序不完全相同,则认为两种方法不同。

注意:数轴包含负整数。

示例1:

输入:startPos = 1, endPos = 2, k = 3
输出:3
解释:存在 3 种从 12 且恰好移动 3 步的方法:
- 1 -> 2 -> 3 -> 2.
- 1 -> 2 -> 1 -> 2.
- 1 -> 0 -> 1 -> 2.
可以证明不存在其他方法,所以返回 3

示例2:

输入: startPos = 2, endPos = 5, k = 10
输出: 0
解释: 不存在从 25 且恰好移动 10 步的方法。

提示:

  • 1 <= startPos, endPos, k <= 1000

解题思路:

只记录上一步走到了哪些坐标还不够,还得记录有多少次走到了上一步的坐标
所以用一个map来记录 key做坐标, value做个数

我的答案:

var numberOfWays = function(startPos, endPos, k) {
    const diff = Math.abs(startPos - endPos);
    let rest = k - diff;
    if(rest < 0 || (rest&1)) return 0;
    
    const mod = (10**9) + 7
    const dp = Array.from({length: k + 1}, ()=> new Map()); //dp: [map]
    dp[0].set(startPos, 1);
    for(let i=1; i<=k; i++) {
        const preMap = dp[i-1]; //上一步的map, key是坐标, value是个数;
        for(const [pos, count] of preMap) { //遍历上一步的坐标和个数
            const prePos = pos - 1; //下一步向前走的坐标
            const nextPos = pos + 1; //下一步向后走的坐标
            const curMap = dp[i];
            if(!curMap.has(prePos)) curMap.set(prePos, 0);
            if(!curMap.has(nextPos)) curMap.set(nextPos, 0);
            //累加
            curMap.set(prePos, (curMap.get(prePos) + count) % mod) 
            curMap.set(nextPos, (curMap.get(nextPos) + count) % mod)
        }
    }
    return dp[k].get(endPos); //返回第k步时 在endPos坐标上的个数
};

最后

如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )