Leetcode 403. Frog Jump 青蛙过河

题目:

一只青蛙想要过河。 假定河流被等分为 x 个单元格,并且在每一个单元格内都有可能放有一石子(也有可能没有)。 青蛙可以跳上石头,但是不可以跳入水中。

给定石子的位置列表(用单元格序号升序表示), 请判定青蛙能否成功过河(即能否在最后一步跳至最后一个石子上)。 开始时, 青蛙默认已站在第一个石子上,并可以假定它第一步只能跳跃一个单位(即只能从单元格1跳至单元格2)。

如果青蛙上一步跳跃了 个单位,那么它接下来的跳跃距离只能选择为 k - 1或 k + 1个单位。 另请注意,青蛙只能向前方(终点的方向)跳跃。

请注意:

  • 石子的数量 ≥ 2 且 < 1100;
  • 每一个石子的位置序号都是一个非负整数,且其 < 231
  • 第一个石子的位置永远是0。

示例 1:

[0,1,3,5,6,8,12,17]

总共有8个石子。
第一个石子处于序号为0的单元格的位置, 第二个石子处于序号为1的单元格的位置,
第三个石子在序号为3的单元格的位置, 以此定义整个数组...
最后一个石子处于序号为17的单元格的位置。

返回 true。即青蛙可以成功过河,按照如下方案跳跃: 
跳1个单位到第2块石子, 然后跳2个单位到第3块石子, 接着 
跳2个单位到第4块石子, 然后跳3个单位到第6块石子, 
跳4个单位到第7块石子, 最后,跳5个单位到第8个石子(即最后一块石子)。

示例 2:

[0,1,2,3,4,8,9,11]

返回 false。青蛙没有办法过河。 
这是因为第5和第6个石子之间的间距太大,没有可选的方案供青蛙跳跃过去。

解题思路:

动态规划问题,模拟青蛙跳的过程,每个石头保存跳到它的步数信息,使用set防止重复,最后判断最后一个石头的set为不为空,如果不为空说明可以到达。

时间复杂度O(n)

代码实现:

class Solution {
    public boolean canCross(int[] stones) {

        if (stones.length == 0) return true;

        HashMap<Integer, HashSet<Integer>> map = new HashMap<Integer, HashSet<Integer>>(stones.length);

        for (int i = 1; i < stones.length; i++) {
            map.put(stones[i], new HashSet<Integer>());
        }

        if (!map.containsKey(1)) return false;
        map.get(1).add(1);

        // 最后一块不需要跳
        for (int i = 1; i < stones.length - 1; i ++) {
            int stone = stones[i];
            for (int step : map.get(stone)) {
                for (int p = -1; p < 2; p ++) {
                    int reach = step + stone + p;
                    if (step + p <= 0) continue;
                    if (reach == stones[stones.length - 1]) {
                        return true;
                    }

                    if (!map.containsKey(reach)) continue;
                    HashSet<Integer> set = map.get(reach);
                    set.add(step + p);
                }
            }
        }

        for (int i = 0; i < stones.length; i ++) {
            int stone = stones[i];
            System.out.print(stone + ": ");
            for (int step : map.get(stone)) {
                System.out.print(step + "| ");
            }
            System.out.println(" ");
        }

        return map.get(stones[stones.length - 1]).size() > 0;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值