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 , return the number of different ways to reach the position endPos starting from startPos , such that you perform exactly steps. Since the answer may be very large, return it modulo .
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:
解题思路
比赛的时候是用动态规划写的,没想到还有数学的解法。
先算一下从起点到终点要走的步数,假设是,即从起点到终点要净走步。假设起点在终点的左边,往右走的步数记为,往左走的步数记为,那么要满足
解得,相当于要从步中选出步向右走,即。算这个组合数可以直接用公式加快速幂求逆元。
AC代码如下,时间复杂度为:
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的做法。
定义状态表示所有从起点花步走到位置的方案的集合,属性就是计数。根据最后一步的不同来划分集合,因此状态转移方程为
还需要注意下标可能会出现负数的情况,因此需要加上一个偏移量。可以发现如果起点在这个位置,那么最多向左步,因此左边界最远为。同理如果起点在这个位置,那么最多向右走步,因此右边界最远为。因此下标的最大长度为,一开始可以给起点和终点加上偏移量。
AC代码如下,时间复杂度为:
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
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16659441.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效