Number of Ways to Reach a Position After Exactly k Steps

Number of Ways to Reach a Position After Exactly k Steps

You are given two positive integers startPos and endPos . Initially, you are standing at position startPos on an infinite number line. With one step, you can move either one position to the left, or one position to the right.

Given a positive integer k, return the number of different ways to reach the position endPos starting from startPos , such that you perform exactly k steps. Since the answer may be very large, return it modulo 109+7.

Two ways are considered different if the order of the steps made is not exactly the same.

Note that the number line includes negative integers.

Example 1:

Input: startPos = 1, endPos = 2, k = 3
Output: 3
Explanation: We can reach position 2 from 1 in exactly 3 steps in three ways:
- 1 -> 2 -> 3 -> 2.
- 1 -> 2 -> 1 -> 2.
- 1 -> 0 -> 1 -> 2.
It can be proven that no other way is possible, so we return 3.

Example 2:

Input: startPos = 2, endPos = 5, k = 10
Output: 0
Explanation: It is impossible to reach position 5 from position 2 in exactly 10 steps.

Constraints:

1startPos,endPos,k1000

 

解题思路

  比赛的时候是用动态规划写的,没想到还有数学的解法。

  先算一下从起点到终点要走的步数,假设是d,即从起点到终点要净走d步。假设起点在终点的左边,往右走的步数记为r,往左走的步数记为l,那么要满足

{rl=dr+l=k

解得r=d+k2,相当于要从k步中选出r步向右走,即Ckr。算这个组合数可以直接用公式加快速幂求逆元。

  AC代码如下,时间复杂度为O(nlogn)

复制代码
 1 class Solution {
 2 public:
 3     int mod = 1e9 + 7;
 4 
 5     int qmi(int a, int k, int p) {
 6         int ret = 1;
 7         while (k) {
 8             if (k & 1) ret = 1ll * ret * a % p;
 9             a = 1ll * a * a % p;
10             k >>= 1;
11         }
12         return ret;
13     }
14 
15     int numberOfWays(int startPos, int endPos, int k) {
16         int d = abs(endPos - startPos);
17         if (d + k & 1 || d > k) return 0;   // 特判掉d和k奇偶不同与无法到达终点的情况
18         int ret = 1, r = d + k >> 1;
19         for (int i = 1, j = k; i <= r; i++, j--) {
20             ret = (1ll * ret * j) % mod * qmi(i, mod - 2, mod) % mod;
21         }
22         return ret;
23     }
24 };
复制代码

  下面再讲讲用dp的做法。

  定义状态f(i,j)表示所有从起点花i步走到位置j的方案的集合,属性就是计数。根据最后一步的不同来划分集合,因此状态转移方程为f(i,j)=f(i1,j1)+f(i1,j+1)

  还需要注意下标可能会出现负数的情况,因此需要加上一个偏移量。可以发现如果起点在1这个位置,那么最多向左500步,因此左边界最远为500。同理如果起点在1000这个位置,那么最多向右走500步,因此右边界最远为1500。因此下标的最大长度为2000,一开始可以给起点和终点加上偏移量500

  AC代码如下,时间复杂度为O(n2)

复制代码
 1 class Solution {
 2 public:
 3     int mod = 1e9 + 7, N = 2010, B = 500;
 4 
 5     int numberOfWays(int startPos, int endPos, int k) {
 6         startPos += B, endPos += B; // 加上偏移量
 7         vector<vector<int>> f(k + 1, vector<int>(N));
 8         f[0][startPos] = 1;
 9         for (int i = 1; i <= k; i++) {
10             for (int j = 0; j < N; j++) {   // 直接枚举加上偏移量后的位置
11                 if (j) f[i][j] = f[i - 1][j - 1];   // 可以从左边走过来
12                 if (j + 1 < N) f[i][j] = (f[i][j] + f[i - 1][j + 1]) % mod; // 可以从右边走过来
13             }
14         }
15         return f[k][endPos];
16     }
17 };
复制代码

 

参考资料

  力扣第309场周赛:https://www.bilibili.com/video/BV1DB4y1G7gX

posted @   onlyblues  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示