给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。
每一步,你可以从下标 i 跳到下标 i + 1 、i - 1 或者 j :
i + 1需满足:i + 1 < arr.lengthi - 1需满足:i - 1 >= 0j需满足:arr[i] == arr[j]且i != j
请你返回到达数组最后一个元素的下标处所需的 最少操作次数 。
注意:任何时候你都不能跳到数组外面。
示例 1:
**输入:**arr = [100,-23,-23,404,100,23,23,23,3,404] **输出:**3 **解释:**那你需要跳跃 3 次,下标依次为 0 ⇒ 4 ⇒ 3 ⇒ 9 。下标 9 为数组的最后一个元素的下标。
示例 2:
**输入:**arr = [7] **输出:**0 **解释:**一开始就在最后一个元素处,所以你不需要跳跃。
示例 3:
**输入:**arr = [7,6,9,6,9,6,9,7] **输出:**1 **解释:**你可以直接从下标 0 处跳到下标 7 处,也就是数组的最后一个元素处。
提示:
1 <= arr.length <= 5 * 10^4-10^8 <= arr[i] <= 10^8
思路
- 仔细阅读题目,其实是一个图的问题。数组每个节点,代表图的 n 个顶点。每个节点和其前后节点都有边。此外,如果节点上的数值相同,也认为两者之间有一条边。所有边的权重都为 1. 要求从节点 1 到节点 n 的最短路径。
- 感觉可以用广度优先搜索(BFS),对每个结点,遍历所有可达的节点,记录到达这个节点时权重之和。最先到达节点 n 时的权重之和,就是答案。
- 用一个 hash 数组记录节点值相同时,对应的索引列表。
- 队列天然适合层次遍历的场景(BFS,树的层次遍历等)
- 也可用双队列(参考题解:灵茶山艾府 - BFS)
Code
class Solution {
public:
/*
参考题解
https://leetcode.cn/problems/jump-game-iv/solutions/3963775/bfspythonjavacgo-by-endlesscheng-hyzz
*/
int minJumps(vector<int>& arr) {
unordered_map<int, vector<int>> val2idx;
for (int i = 0; i < arr.size(); ++i) {
val2idx[arr[i]].push_back(i);
}
vector<int8_t> visited(arr.size(), 0);
queue<pair<int, int>> q; // <index, step>
q.push({0, 0});
visited[0] = 1;
while (!q.empty()) {
auto [idx, step] = q.front();
q.pop();
if (idx == arr.size() - 1) return step;
// 向前跳跃
if (idx - 1 >= 0 && !visited[idx-1]) {
q.push({idx - 1, step + 1});
visited[idx-1] = 1;
}
// 向后跳跃
if (idx + 1 < arr.size() && !visited[idx+1]) {
q.push({idx + 1, step + 1});
visited[idx+1] = 1;
}
// 等值跳跃
for (auto next_idx : val2idx[arr[idx]]) {
if (!visited[next_idx]) {
q.push({next_idx, step + 1});
visited[next_idx] = 1;
}
}
// add this to avoid TLE.
val2idx.erase(arr[idx]);
}
return -1;
}
};