• 80跳跃游戏 IV(1345)


    作者: Turbo时间限制: 1S章节: 宽度优先搜索

    晚于: 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)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*/
  • 相关阅读:
    14_最长公共前缀_字符串_简单
    5. 最长回文子串_字符串_中等
    187. 重复的DNA序列_字符串_中等
    lr_bn_batchsize_deformable convolution_Hard negative mining
    彻底搞懂HTTPs的加密原理
    20. 有效的括号_字符串_简单
    13_罗马数字转整数_字符串_简单
    202_快乐数_数组_简答
    组件
    World
  • 原文地址:https://www.cnblogs.com/zmmm/p/13654696.html
Copyright © 2020-2023  润新知