题目
给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。
每一步,你可以从下标 i 跳到下标:
i + 1 满足:i + 1 < arr.length
i - 1 满足:i - 1 >= 0
j 满足:arr[i] == arr[j] 且 i != j
请你返回到达数组最后一个元素的下标处所需的最少操作次数 。
Solutions
BFS搜索解法
- 下标 i 可以跳的位置是前一个位置、后一个位置、与nums[i]相等的位置(前提是符合条件:下标在数组范围内且不在队列中)。
- 用hash表存储值为value的所有下标。
在每一次取出队头后,假设对应下标为now_index,去访问hash[nums[now_index]]中所包含的所有未被访问过的下标并加入队列中。 - 可以优化的是:
因为BFS特点是每到达一个结点不会再访问这个结点且加入队列后步数是增加的,所以如果已经将一个相同的值元素的所有位置都加入队列后,无需再去穷举访问值相同的所有位置下标。 - 利用一个steps数组记录到达下标i需要走的最少步数。
- 因为每一个结点只访问一次所以时间复杂度为O(n),使用了三个长度为n的数组和一个最大长度为n的队列,所以空间复杂度为O(n)
代码
class Solution {
public:
int minJumps(vector<int>& arr) {
if(arr.size()==1)
return 0;
int end_index=arr.size();
unordered_map<int,vector<int>> same; //相同值映射
vector<bool> vis(end_index,false);
vector<int> steps(end_index,INT_MAX-1);//记录到达下标i的最短步数
queue<int> q;
for(int i=0;i<end_index;i++){
same[arr[i]].push_back(i);
}
steps[end_index-1]=0;
q.push(end_index-1);
while(!q.empty()){
int now_index=q.front();
q.pop();
vis[now_index]=true;
if(now_index-1>=0&&!vis[now_index-1]){
steps[now_index-1]=min(steps[now_index-1],steps[now_index]+1);
q.push(now_index-1);
}
if(now_index+1<end_index&&!vis[now_index+1]){
steps[now_index+1]=min(steps[now_index+1],steps[now_index]+1);
q.push(now_index+1);
}
if(same.find(arr[now_index])!=same.end()){
for(int index:same[arr[now_index]]){
if(!vis[index]){
steps[index]=min(steps[index],steps[now_index]+1);
q.push(index);
}
}
same.erase(arr[now_index]);
}
}
return steps[0];
}
};