算法:回溯和动态规划解决每次移动一步最终回到原地1269. Number of Ways to Stay in the Same Place After Some Steps

LeetCode全集请参考:LeetCode Github 大全

题目

1269. Number of Ways to Stay in the Same Place After Some Steps

You have a pointer at index 0 in an array of size arrLen. At each step, you can move 1 position to the left, 1 position to the right in the array or stay in the same place (The pointer should not be placed outside the array at any time).

Given two integers steps and arrLen, return the number of ways such that your pointer still at index 0 after exactly steps steps.

Since the answer may be too large, return it modulo 10^9 + 7.

Example 1:

Input: steps = 3, arrLen = 2
Output: 4
Explanation: There are 4 differents ways to stay at index 0 after 3 steps.
Right, Left, Stay
Stay, Right, Left
Right, Stay, Left
Stay, Stay, Stay

Example 2:

Input: steps = 2, arrLen = 4
Output: 2
Explanation: There are 2 differents ways to stay at index 0 after 2 steps
Right, Left
Stay, Stay

Example 3:

Input: steps = 4, arrLen = 2
Output: 8

Constraints:

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

回溯递归解决

分析:移动的三种方案可以转换为数字右移+1,不动0,左移-1。 很容易就想到用回溯递归的方式解决。退出的条件有两个:

  1. 步数用完steps == 0 ,如果位置为0则表示一种方案,返回1,否则表示不符合要求,返回0;
  2. 超过边界sum < 0 || sum >= arrLen,实际上还有优化的空间最大步数不超过steps的一半,或者arrLen。Math.min(steps/2 + 1, arrLen)
public int numWays(int steps, int arrLen) {
    return helper(steps, arrLen, 0);
  }

  private int helper(int steps, int arrLen, int sum) {
    // check edge
    if (sum < 0 || sum >= arrLen) {
      return 0;
    }
    // exit
    if (steps == 0) {
      return sum == 0 ? 1 : 0;
    }

    int next = steps - 1;
    return helper(next, arrLen, sum + 1) + helper(next, arrLen, sum) + helper(next, arrLen, sum - 1);
  }

这里不考虑时间复杂度,可以解决问题,在LeetCode提交会超时。

动态规划

如果我们将dp状态选择为dp[steps][position],则可以从该状态选择:

  • 不动。然后我们消耗一步,并停留在同一位置=>dp[steps-1][position]
  • 向右走。然后,我们走了一步,然后向右走=>dp[steps-1][position+1]
  • 向左走(如果不在零位置)。然后我们消耗一步,然后向左走=>if position > 0 then dp[steps-1][position-1]

然后我们的状态可以计算为:dp[steps][position] = dp[steps-1][position] + dp[steps-1][position+1] + dp[steps-1][position-1]

当只有一步作为基本案例时,我们可以使用该案例。这些情况是:

  • 我们处于零位,只有一步,那么只有一种方法(停留)=> dp[1][0] = 1
  • 我们处于第一位置,只有一步,然后只有一种方法(向左走)=> dp[1][1] = 1

请注意,我们只能进行尽可能多的步骤。例如,对于500步,我们只能到达第500个位置,而arrLen是否为99999999则无关紧要。因此,我们使用它来避免内存/时间限制。min(steps,arrLen)

public int numWaysWithDP(int steps, int arrLen) {
    //int MOD = 1000_000_007;
    final int MOD = (int)1e9 + 7;
    int maxPos = Math.min(steps / 2 + 1, arrLen);
    long[][] dp = new long[steps + 1][maxPos + 1];

    dp[1][0] = 1;
    dp[1][1] = 1;

    for (int i = 2; i <= steps; i++) {
      for (int k = 0; k < maxPos; k++) {
        dp[i][k] = (dp[i - 1][k] + dp[i - 1][k + 1] + (k > 0 ? dp[i - 1][k - 1] : 0)) % MOD;
      }
    }

    return (int) dp[steps][0];
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值