0%

403. 青蛙过河

403.青蛙过河

题目描述:

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

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

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

数据范围:

$2 \le stones.len \le 2000, 0 \le stones[i] \le 2^{31} - 1, stones[0] = 0$

严格升序

题解:

设计dp状态 $dp[i][j]$ 表示当前在 $i$ 下标,上一步跳了 $j$ 个单位,但是 $j$ 的范围不确定,可以使用 unordered_map。然后枚举上一步跳到了 $k, k\in [0, i)$ ,然后两者之间的距离是 $d = stones[i] - stones[k]$ ,如果 $dp[k][d - 1] \or dp[k][d] \or dp[k][d + 1]$ ,那么 $dp[i][d] = true$ 。

后续发现,每次最多比上一次多跳一个单位,因为 $0$ 是 $1$ ,则 $i$ 最多是 $i + 1$ 。可以直接使用二维数组,不用使用 unordered_map

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
auto optimize_cpp_stdio = []()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
class Solution
{
public:
const static int maxn = 1e5 + 10;
const static int maxm = 1e5 + 10;
const static long long mod = 1e9 + 7;
const long long INF_LL = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
bool canCross(vector<int> &stones)
{
int n = stones.size();
if (stones[1] - stones[0] > 1)
return false;
if (n == 2)
return true;
vector<vector<int>> dp(n, vector<int>(n)); // 记录 dp[i][pre_k]
dp[1][1] = true;
for (int i = 2; i < n; ++i)
{
for (int j = i - 1; j >= 1; --j)
{
int k = stones[i] - stones[j];
if (k > j + 1)
continue;
dp[i][k] = dp[j][k - 1] || dp[j][k] || dp[j][k + 1];
if (i == n - 1 && dp[i][k])
return true;
}
}
return false;
}
};