题目链接
题目描述
给你有一个 非负 整数 k 。有一个无限长度的台阶,最低 一层编号为 0 。
Alice 有一个整数 jump ,一开始值为 0 。Alice 从台阶 1 开始,可以使用 任意 次操作,目标是到达第 k 级台阶。假设 Alice 位于台阶 i ,一次 操作 中,Alice 可以:
向下走一级到 i - 1 ,但该操作 不能 连续使用,如果在台阶第 0 级也不能使用。
向上走到台阶 i + 2jump 处,然后 jump 变为 jump + 1 。
请你返回 Alice 到达台阶 k 处的总方案数。
注意,Alice 可能到达台阶 k 处后,通过一些操作重新回到台阶 k 处,这视为不同的方案。
示例 1:
输入:k = 0
输出:2
解释:
2 种到达台阶 0 的方案为:
Alice 从台阶 1 开始。
执行第一种操作,从台阶 1 向下走到台阶 0 。
Alice 从台阶 1 开始。
执行第一种操作,从台阶 1 向下走到台阶 0 。
执行第二种操作,向上走 20 级台阶到台阶 1 。
执行第一种操作,从台阶 1 向下走到台阶 0 。
示例 2:
输入:k = 1
输出:4
解释:
4 种到达台阶 1 的方案为:
Alice 从台阶 1 开始,已经到达台阶 1 。
Alice 从台阶 1 开始。
执行第一种操作,从台阶 1 向下走到台阶 0 。
执行第二种操作,向上走 20 级台阶到台阶 1 。
Alice 从台阶 1 开始。
执行第二种操作,向上走 20 级台阶到台阶 2 。
执行第一种操作,向下走 1 级台阶到台阶 1 。
Alice 从台阶 1 开始。
执行第一种操作,从台阶 1 向下走到台阶 0 。
执行第二种操作,向上走 20 级台阶到台阶 1 。
执行第一种操作,向下走 1 级台阶到台阶 0 。
执行第二种操作,向上走 21 级台阶到台阶 2 。
执行第一种操作,向下走 1 级台阶到台阶 1 。
提示:
0 <= k <= 109
求解思路
- 记忆化搜索:
- 每次搜索需要记录的变量:
i
表示当前状态所在台阶数,j
表示使用操作二的次数,pre
表示上一次的操作是否使用了操作一,mem
用来记忆搜索的结果。 - 状态转移方程:(枚举当前所能进行的操作)
- 如果进行操作二,则接下来要解决的问题为: d f s ( i + 2 j , j + 1 , 0 ) dfs(i+2^j,j+1,0) dfs(i+2j,j+1,0)。
- 如果当前允许执行操作一 ( p r e = = 0 (pre==0 (pre==0 & i > 0 ) i>0) i>0),接下来要解决的问题为: d f s ( i − 1 , j , 1 ) dfs(i-1,j,1) dfs(i−1,j,1)。
- 如果 i = = k i==k i==k,说明此时到达了终点,需要将结果加一。
- 因为到达了台阶 k k k 之后还可以继续操作,所以 i = = k i==k i==k 并不是递归的终点。
- 递归的边界为 i > k + 1 i>k+1 i>k+1,由于操作一不能连续使用,因此只要超过目标台阶两阶,则再也无法到达终点。
- 每次搜索需要记录的变量:
实现代码
class Solution {
public int waysToReachStair(int k) {
return dfs(1, 0, 0, k, new HashMap<>());
}
private int dfs(int i, int j, int pre, int k, Map<Long, Integer> mem) {
if (i > k + 1) {
return 0;
}
long mask = (long)i << 32 | j << 1 | pre; // 状态压缩
if (mem.containsKey(mask)) {
return mem.get(mask);
} else {
int res = i == k ? 1 : 0;
res += dfs(i + (1 << j), j + 1, 0, k, mem); // 操作二
if (pre == 0 && i > 0) {
res += dfs(i - 1, j, 1, k, mem); // 操作一
}
mem.put(mask, res); // 记忆化
return res;
}
}
}