作者:
晚于: 2020-08-26 12:00:00后提交分数乘系数50%
截止日期: 2020-09-02 12:00:00
问题描述 :
给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。
每一步,你可以从下标 i 跳到下标:
i + 1 满足:i + 1 < arr.length
i - 1 满足:i - 1 >= 0
j 满足: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 处,也就是数组的最后一个元素处。
示例 4:
输入:arr = [6,1,9]
输出:2
示例 5:
输入:arr = [11,22,7,7,7,7,7,7,7,22,13]
输出:3
输入说明 :
首先输入数组arr的长度n,
然后输入n个整数,以空格分隔。
1 <= n <= 5 * 10^4
-10^8 <= arr[i] <= 10^8
输出说明 :
输出一个整数,表示到达数组最后一个元素的下标处所需的最少操作次数
输入范例 :
输出范例 :
#include <iostream> #include <vector> #include <queue> #include <unordered_map> using namespace std; class Solution { public: int minJumps(vector<int>& arr) { int len=arr.size(); vector<int> dis(len,INT_MAX); vector<int> visited(len,0) ;//标记是否被访问 queue<int> q; unordered_map<int,vector<int>> m; for(int i=0;i<len-1;i++) m[arr[i]].push_back(i); q.push(len-1); dis[len-1]=0; while(!q.empty()) { int front =q.front(); q.pop(); if(front-1>=0&&!visited[front-1]&&m.find(arr[front-1])!=m.end()) { dis[front-1]=min(dis[front-1],dis[front]+1); visited[front-1]=1; q.push(front-1); } if(front+1<len&&!visited[front+1]&&m.find(arr[front+1])!=m.end()) { dis[front+1]=min(dis[front+1],dis[front]+1); visited[front+1]=1; q.push(front+1); } if(m.find(arr[front])!=m.end()) { for(int it:m[arr[front]]) { if(!visited[it]) { visited[it]=1; dis[it]=min(dis[front]+1,dis[it]); q.push(it); } } m.erase(arr[front]);//不加就会超时, 去掉标记过的,访问过的值直接清理掉 } } return dis[0]; } }; int main() { vector<int> arr; int n,data; cin>>n; for(int i=0; i<n; i++) { cin>>data; arr.push_back(data); } int result=Solution().minJumps(arr); cout<<result; return 0; } /* https://leetcode-cn.com/problems/jump-game-iv/solution/wei-shi-yao-bfsyi-ji-zen-yang-on-by-tian-ye/ 题目要求计算从第一个元素跳到最后一个元素最少的操作次数。首先容易想到的是,坐标位于最后一个元素时,结果应为0,因为不用任何操作;对于这个元素紧挨着的左右元素(此时只存在左边的元素),它的操作数是1,因为只需要跳一次就跳到了最后;同理,对于数组里值和最后一个元素相等的那些数,他们的操作数都是1。 然后,对于倒数第二个元素,它的操作数前一步已经求得为1,它右边数的结果也已经知道了,是0;它左边的数如果不等于最后一个数,那么它跟最后一个数的距离应为2。这里距离的意思是指操作次数,即跳两次才能到达最后一个数;同样,和倒数第二个数相等的那些元素最小的操作数也都是1+1=2. 这样,可以理解为最后一个数所在层数为0,第1层就是挨着它的元素以及值和它相等的那些数,第2层就是第一层挨着的元素以及值和第一层元素相等的那些数...按层次依次往上加。因为题目要求最少操作数,对于“挨着它的元素”如果前面已经求出了距离(层数),这时就不用再去算了,因为+1之后结果只会更大。例如,用一个数组dis[]表示每一个元素对应的最小操作数,初始化一个大数,如果对于元素i它左边有dis[i-1]等于这个大数,就表明i-1位置还没有求,于是dis[i-1]=dis[i]+1;如果dis[i-1]不等于这个大数就说明左边的元素前面已经算过了,就不要再去给它+1。 为了去找数组中和某一个数相等的所有元素位置,使用HashMap来存下所有值和相应位置(列表)的映射,可以避免一遍遍遍历这个数组去寻找。 (这时候你就可以自己动手去写了,小总结:一个数组存结果,一个Map映射和一个队列来广度优先搜索) 现在写出的代码运行那几个试例是没问题的,不过提交的时候会遇到一个满页是7,最后一个数是13的测例,可能会超时。这里还可以继续优化:对于那堆7,从倒数第二个元素开始其实就已经算出了他们的距离是[2,2,...,2,1,0],每次他都会把新出现的7放入队列,然后又遍历一遍7所在的所有位置。于是可以用一个数组visited[]来记录这个数是否被访问(计算)过,如果已经访问过了就没必要再去map里遍历它对应的所有位置了。 作者:tian-ye 链接:https://leetcode-cn.com/problems/jump-game-iv/solution/wei-shi-yao-bfsyi-ji-zen-yang-on-by-tian-ye/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*/