0
点赞
收藏
分享

微信扫一扫

力扣1345——跳跃游戏 IV(BFS+无向图)

程序小小黑 2022-01-21 阅读 133

题目(困难)

给你一个整数数组 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

提示:

1 <= arr.length <= 5 * 10^4
-10^8 <= arr[i] <= 10^8

解题思路

一个位置可由左边,右边,对应数值的最小步数,三处更新而来,所以传统动态规划的搞不定了
dp[i] = min(dp[i], dp[i-1]+1, dp[i+1]+1, minstep[val]+1)
所以需要BFS探索的来,对于每个位置,往下走一步来探索同属一个值的所有节点们,探索他的左右两边;因此需要建图,建立值到他的索引们的映射。
因为这个过程会重复遇到节点,如果已访问过,肯定之前的步数更少,再次访问就不用实际探索,所以需要一个set来存已访问节点;
并且如果将一个值的所有节点都探索了,其实也就可由从图中去掉该值,减少重复判断,因为判断了也是已访问,不然会超时。

代码

class Solution {
public:
    queue<pair<int,int> > q;    //队列存索引和到该索引的步数
    unordered_set<int> vis;     //存已访问过的节点,因为以前能访问过的步数肯定更小,不必再进队
    void visit(int id, int step) {
        if(!vis.count(id)) {
            vis.insert(id);
            q.push({id, step});
        }
    }
    int minJumps(vector<int>& arr) {
        int n = arr.size();
        unordered_map<int, vector<int>> hash;   //值到索引们的映射
        for(int i = 0; i < n; i++) hash[arr[i]].push_back(i);
        q.push({0, 0});
        vis.insert(0);
        while(!q.empty()) {
            auto [id, step] = q.front();
            q.pop();
            if(id == n-1) return step;  //到达目标
            step++;
            if(hash.count(arr[id])) for(auto x : hash[arr[id]]) visit(x, step);
            hash.erase(arr[id]);     //该值对应的索引们都访问过了,避免下次判断,不然会超时
            if(id-1 >= 0) visit(id-1, step);
            if(id+1 < n) visit(id+1, step);
        }
        return 0;
    }
};
举报

相关推荐

0 条评论