【LeetCode:3154】到达第 K 级台阶的方案数(Java)

题目链接

题目描述

给你有一个 非负 整数 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

求解思路

  • 记忆化搜索:
    1. 每次搜索需要记录的变量:i表示当前状态所在台阶数,j表示使用操作二的次数,pre表示上一次的操作是否使用了操作一,mem用来记忆搜索的结果。
    2. 状态转移方程:(枚举当前所能进行的操作)
      1. 如果进行操作二,则接下来要解决的问题为: d f s ( i + 2 j , j + 1 , 0 ) dfs(i+2^j,j+1,0) dfs(i+2j,j+1,0)
      2. 如果当前允许执行操作一 ( 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(i1,j,1)
      3. 如果 i = = k i==k i==k,说明此时到达了终点,需要将结果加一。
      4. 因为到达了台阶 k k k 之后还可以继续操作,所以 i = = k i==k i==k 并不是递归的终点。
      5. 递归的边界为 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;
        }
        
    }
}

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值