题目
给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。
每一步,你可以从下标 i 跳到下标:
- i + 1 满足:i + 1 < arr.length
- i - 1 满足:i - 1 >= 0
- j 满足:arr[i] == arr[j] 且 i != j
请你返回到达数组最后一个元素的下标处所需的 最少操作次数 。
注意:任何时候你都不能跳到数组外面。
来源:力扣(LeetCode)
解答
遍历时,有三个方向,一个是向左,一个是向右,一个是跳向等值的数。
从头开始进行BFS即可,同时利用哈希表来遍历等值的元素。
具体代码及思路如下:
class Solution {
public:
int minJumps(vector<int> &arr) {
int n = arr.size();
unordered_map<int, vector<int>> mp; // 记录相同值所包含的下标都有几个
vector<int> all(n, -1); // 记录每一个位置最小步数
queue<int> q; // 记录遍历内容
// 将arr所有值对应下标记录到哈希表中,通过倒序记录,保证map先访问的是同值的最后一个元素
for (int i = n - 1; i >= 0; --i) {
mp[arr[i]].push_back(i);
}
all[0] = 0; // 起止点在0,所以第一个值步数为0
q.push(0); // 从第0个下标开始遍历,将其放入队列
// 队列不空,表示未遍历完或未达到最后一个值
while (!q.empty()) {
// 元素出队,表示当前遍历到的元素
auto cur = q.front(); // 当前遍历下标
q.pop();
if (cur == n - 1) {
return all[cur];
}
// 检查右侧元素
// == -1 表示未到达过
if (cur + 1 < n && all[cur + 1] == -1) {
q.push(cur + 1);
all[cur + 1] = all[cur] + 1;
}
// 左侧元素
if (cur - 1 >= 0 && all[cur - 1] == -1) {
q.push(cur - 1);
all[cur - 1] = all[cur] + 1;
}
// 等值元素
auto same = mp[arr[cur]];
for (auto tmp: same) {
if (all[tmp] == -1) {
q.push(tmp);
all[tmp] = all[cur] + 1;
}
}
// 将等值元素都删除,因为已经更新过步数了,
// 如果后续还遇到该值,更新步数一定大于当前更新值(这样做是错误的)
// 所以直接从哈希表中去除
mp.erase(arr[cur]);
}
return -1;
}
};