问题:
一只青蛙想要过河。 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有)。
青蛙可以跳上石子,但是不可以跳入水中。给你石子的位置列表stones(用单元格序号升序表示),请判定青蛙能否成功过河(即能否在最后一步跳至最后一块石子上)。
开始时,青蛙默认已站在第一块石子上,并可以假定它第一步只能跳跃一个单位(即只能从单元格 1 跳至单元格 2 )。
如果青蛙上一步跳跃了k个单位,那么它接下来的跳跃距离只能选择为k - 1、k或k + 1个单位。另请注意,青蛙只能向前方(终点的方向)跳跃。
示例 1:输入:stones = [0,1,3,5,6,8,12,17] 输出:true 解释:青蛙可以成功过河,按照如下方案跳跃:跳 1 个单位到第 2 块石子, 然后跳 2 个单位到第 3 块石子, 接着 跳 2 个单位到第 4 块石子, 然后跳 3 个单位到第 6 块石子, 跳 4 个单位到第 7 块石子, 最后,跳 5 个单位到第 8 个石子(即最后一块石子)。
示例 2:输入:stones = [0,1,2,3,4,8,9,11] 输出:false 解释:这是因为第 5 和第 6 个石子之间的间距太大,没有可选的方案供青蛙跳跃过去。
提示:2 <= stones.length <= 20000 <= stones[i] <= 231- 1stones[0] == 0
解答思路:
以下是一个Java语言的解决方案,使用动态规划来解决这个问题:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class FrogJump {
public boolean canCross(int[] stones) {
if (stones == null || stones.length == 0) return false;
if (stones[1] != 1) return false; // 青蛙第一步只能跳一个单位
Map<Integer, Set<Integer>> map = new HashMap<>(); // 记录每个石子能跳到的步数
for (int stone : stones) {
map.put(stone, new HashSet<>());
}
map.get(0).add(1); // 初始位置,只能跳1步
for (int stone : stones) {
for (int k : map.get(stone)) {
// 能跳到当前石子的步数k,下一步可以跳k-1, k, k+1
for (int step = k - 1; step <= k + 1; step++) {
if (step > 0 && map.containsKey(stone + step)) {
map.get(stone + step).add(step);
}
}
}
}
// 检查最后一块石子是否有可达的步数
return map.get(stones[stones.length - 1]) != null && !map.get(stones[stones.length - 1]).isEmpty();
}
public static void main(String[] args) {
FrogJump frogJump = new FrogJump();
int[] stones1 = {0,1,3,5,6,8,12,17};
int[] stones2 = {0,1,2,3,4,8,9,11};
System.out.println("Test Case 1: " + frogJump.canCross(stones1)); // 应输出 true
System.out.println("Test Case 2: " + frogJump.canCross(stones2)); // 应输出 false
}
}
解释:
- 使用一个HashMap来存储每个石子能跳到的步数集合。
- 初始化时,青蛙站在第一个石子上,只能跳1步。
- 对于每个石子,检查所有能跳到它的步数,然后尝试用k-1, k, k+1步继续跳跃。
- 如果最后一块石子有可达的步数,则青蛙可以过河。
这个算法的时间复杂度是O(n^2),空间复杂度是O(n),其中n是石子的数量。在题目给定的范围内,这个算法是有效的。
(文章为作者在学习java过程中的一些个人体会总结和借鉴,如有不当、错误的地方,请各位大佬批评指正,定当努力改正,如有侵权请联系作者删帖。)