1. 问题背景与核心挑战
LeetCode 403题"青蛙过河"是一个经典的动态规划问题,题目描述如下:一只青蛙想要过河,河中有若干石头,青蛙只能在这些石头上跳跃。初始时青蛙位于第一块石头(位置0),第一次跳跃只能跳1个单位。如果青蛙上一次跳跃了k个单位,那么它下一次只能跳k-1、k或k+1个单位。我们需要判断青蛙是否能够成功到达最后一块石头。
这个问题的难点在于如何处理跳跃步长的动态变化约束。与常规的跳跃游戏不同,青蛙的每次跳跃步长都受到前一次跳跃步长的严格限制,这使得简单的贪心算法无法适用。我在实际解题过程中发现,很多初学者容易陷入暴力递归的陷阱,导致时间复杂度爆炸。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路分析与算法选择
2.1 暴力递归法的局限性
最直观的解法是尝试所有可能的跳跃路径。对于每个石头位置和可能的跳跃步长,递归地尝试三种可能的下一步跳跃(k-1, k, k+1)。这种方法虽然理论上可行,但时间复杂度高达O(3^n),当石头数量较多时(比如n>30),计算时间会变得不可接受。
我在第一次尝试时就用这种方法,结果在测试用例stones = [0,1,2,3,...,999,1000]上直接超时。这个教训让我意识到必须寻找更高效的算法。
2.2 动态规划的正确方向
动态规划是解决这类具有重叠子问题和最优子结构特性的问题的理想选择。我们可以定义dp[i][k]表示青蛙能否通过跳k步到达第i个石头。状态转移方程为:
对于每个石头i和可能的步长k,检查是否存在前一个石头j,使得stones[i]-stones[j]=k,并且dp[j][k-1]、dp[j][k]或dp[j][k+1]中至少有一个为真。
这种方法的复杂度降到了O(n^2),因为最多有n个石头,每个石头最多有n种可能的步长(因为步长最多从1增长到n-1)。
3. 详细实现与优化技巧
3.1 基础DP实现
java复制public boolean canCross(int[] stones) {
int n = stones.length;
boolean[][] dp = new boolean[n][n];
dp[0][0] = true;
for (int i = 1; i < n; i++) {
