当前位置: 面试刷题>> 青蛙跳 (经典算法题500道)


### 题目描述补充 **青蛙跳问题**: 有一只小青蛙,想要从河的一边跳到另一边。河的宽度被划分为`n`个连续的格子(从0到n-1),每个格子可以是空的(小青蛙可以跳过去),也可以是石头(小青蛙不能跳上去)。给定一个数组`stones`,其中`stones[i]`表示第`i`个石头在河岸上的位置(位置从0开始计数),请问小青蛙能否跳到河的对岸(即位置`n-1`),如果可以,返回任意一种跳跃序列;如果不可以,返回空数组。 **注意**: - 小青蛙每次可以跳过一个或两个格子。 - 小青蛙的起始位置在`stones[0]`,结束位置是`n-1`。 - 如果存在多种跳跃序列,返回任意一种即可。 ### 示例 **输入**: ``` stones = [0, 1, 3, 5, 6, 8, 12, 17] n = 20 ``` **输出**: ``` [0, 1, 3, 5, 6, 8, 12, 17] # 这是一种可能的跳跃序列 ``` ### PHP 代码示例 ```php function canCross($stones, $n) { $dp = array_fill(0, $n, array_fill(0, 2, false)); // dp[i][0] 表示能否一步跳到i,dp[i][1] 表示能否两步跳到i $stoneSet = array_flip($stones); // 将stones数组转为哈希集合,便于快速查找 if (!isset($stoneSet[0])) return []; $dp[0][0] = true; // 起始位置可以一步跳到 foreach ($stones as $stone) { if ($stone > 2) { // 检查是否可以一步或两步从前一个位置跳过来 if (isset($stoneSet[$stone - 1]) && $dp[$stone - 1][0]) { $dp[$stone][0] = true; $path[] = $stone; // 记录路径,但注意这里不是直接返回,因为需要遍历完所有石头 } if (isset($stoneSet[$stone - 2]) && $dp[$stone - 2][1]) { $dp[$stone][1] = true; } } // 更新两步可达的状态 if ($stone > 1) { $dp[$stone][1] = $dp[$stone][1] || ($dp[$stone - 1][0] && isset($stoneSet[$stone - 2])); } } // 回溯构建路径(如果需要的话,这里简化为返回是否可达及一种可能的结束位置) if ($dp[$n - 1][0] || $dp[$n - 1][1]) { // 假设只需要判断是否可达,并返回最后一个位置作为示例 return [$n - 1]; // 注意:实际面试中,可能需要回溯算法来构建完整的跳跃序列 } return []; } // 注意:上面的代码主要展示了动态规划的思路,并简化了路径的构建部分。 // 完整构建路径需要回溯算法,可能不适合在此直接展示完整代码。 ``` ### Python 代码示例 ```python def canCross(stones, n): dp = [[False, False] for _ in range(n)] stone_set = set(stones) dp[0][0] = True for stone in stones: if stone > 2: if stone - 1 in stone_set and dp[stone - 1][0]: dp[stone][0] = True if stone - 2 in stone_set and dp[stone - 2][1]: dp[stone][1] = True if stone > 1: dp[stone][1] = dp[stone][1] or (dp[stone - 1][0] and stone - 2 in stone_set) # 假设只需要判断是否可达 if dp[n - 1][0] or dp[n - 1][1]: return True # 实际面试中可能需要构建路径 return False # 注意:此Python示例仅判断了是否可达,未构建路径。 ``` ### JavaScript 代码示例 ```javascript function canCross(stones, n) { const dp = Array.from({ length: n }, () => [false, false]); const stoneSet = new Set(stones); dp[0][0] = true; for (const stone of stones) { if (stone > 2) { if (stoneSet.has(stone - 1) && dp[stone - 1][0]) { dp[stone][0] = true; } if (stoneSet.has(stone - 2) && dp[stone - 2][1]) { dp[stone][1] = true; } } if (stone > 1) { dp[stone][1] = dp[stone][1] || (dp[stone - 1][0] && stoneSet.has(stone - 2)); } } return dp[n - 1][0] || dp[n - 1][1]; // 仅判断是否可达 // 注意:构建完整路径需要额外的回溯逻辑。 } ``` **码小课**:在码小课网站中,你可以找到更多关于动态规划、回溯算法以及算法面试题目的详细解析和实战演练,帮助你更好地掌握这些算法技巧,提升编程和解题能力。
推荐面试题