恰好移动K步到达某一位置的方法数目
2400. 恰好移动 k 步到达某一位置的方法数目 - 力扣(LeetCode)
-
给你两个 正 整数
startPos
和endPos
。最初,你站在 无限 数轴上位置startPos
处。在一步移动中,你可以向左或者向右移动一个位置。- 给你一个正整数
k
,返回从startPos
出发、恰好 移动k
步并到达endPos
的 不同 方法数目。由于答案可能会很大,返回对109 + 7
取余 的结果。 - 如果所执行移动的顺序不完全相同,则认为两种方法不同。
注意:数轴包含负整数。
示例 1:
输入:startPos = 1, endPos = 2, k = 3 输出:3 解释:存在 3 种从 1 到 2 且恰好移动 3 步的方法: - 1 -> 2 -> 3 -> 2. - 1 -> 2 -> 1 -> 2. - 1 -> 0 -> 1 -> 2. 可以证明不存在其他方法,所以返回 3 。
示例 2:
输入:startPos = 2, endPos = 5, k = 10 输出:0 解释:不存在从 2 到 5 且恰好移动 10 步的方法。
提示:
1 <= startPos, endPos, k <= 1000
- 给你一个正整数
-
先思考暴力搜索是否可以
- 一个点只能往左或者往右行动,可以考虑递归求左边的方法数+右边的方法数
- 递归的中止点,步数为0,若刚好到达,则这是一个方法返回1,否则返回0
class Solution {
public:
int numberOfWays(int startPos, int endPos, int k) {
return DFS(startPos,endPos,k);
}
int DFS(int startPos, int endPos, int k) {
if(k == 0) {
if(startPos == endPos){
return 1;
}
return 0;
}
return DFS(startPos-1,endPos,k-1)+DFS(startPos+1,endPos,k-1);
}
};
-
暴力递归少数据证明正确,但是超时,考虑优化,即看看是否有重复计算的过程
-
- 存在重复计算过程,使用缓存记录 -> 记忆化搜索
class Solution { public: vector<vector<int>> dp; const int MAX = pow(10,9)+7; int numberOfWays(int startPos, int endPos, int k) { //dp数组大小 dp[startpos][k] //考虑到 startpos-k 和startpos+k , 第一个大小为2k+1 //第二个为k+1 dp.resize(2*k + 1, vector<int>(k+1,-1)); //调整startpos 至 0-2k return DFS(k,endPos-startPos+k,k); } int DFS(int startPos, int endPos, int k) { if(dp[startPos][k] != -1) return dp[startPos][k]; if(k == 0) { if(startPos == endPos){ return 1; } return 0; } return dp[startPos][k] = (DFS(startPos-1,endPos,k-1)+DFS(startPos+1,endPos,k-1))%MAX; } };
-
根据记忆化搜索的
dp
数组推导动态规划的状态转移方程
class Solution {
public:
vector<vector<int>> dp;
const int MAX = pow(10,9)+7;
int numberOfWays(int startPos, int endPos, int k) {
dp.resize(2*k + 1, vector<int>(k+1,-1));
return DFS(k,endPos-startPos+k,k);
}
int DFS(int startPos, int endPos, int k) {
if(dp[startPos][k] != -1) return dp[startPos][k];
if(k == 0) {
if(startPos == endPos){
return 1;
}
return 0;
}
return dp[startPos][k] = (DFS(startPos-1,endPos,k-1)+DFS(startPos+1,endPos,k-1))%MAX;
}
};