力扣 1345. 跳跃游戏 IV

题目来源:https://leetcode-cn.com/problems/jump-game-iv/

大致题意:
给一个数组,从第一个元素出发,算出在如下规则下最少多少步可以到达最后一个元素

  • 移到下一个元素
  • 移到上一个元素
  • 移到一个相同的元素位置

思路

最少多少步,就容易想到最短路径,最短路径就需要图或者树,可是这是一个数组

不过可以利用规则,想象成图:

  • 把该数组想象成一个无向图
  • 一个元素与它的相邻元素以及相同元素之间构成边

有了图,就可以开始遍历了,可以使用 BFS 来搜索

常规 BFS 的时间复杂度为点数 + 边数的和,这样的话会超时,对于该题可以进行剪枝:

  • 相同元素之间的边只用遍历一次即可,所以可以在遍历到一个节点时,将其值相同的节点直接的边删除–也就是不再遍历到这些边
  • 可以用哈希表实现该操作,首先遍历数组,将所有值相同的元素放入一个集合中,然后再搜索时,当第一次遍历到一个节点值时,就将值对应的元素从哈希表中取出,之后就不再进行该操作
BFS + 剪枝
  1. 遍历数组,将相同元素放入哈希表中,key 为元素值,value 为该元素索引的集合
  2. BFS 遍历。对于每次搜索到的节点,先判断哈希表中是否有对应的键,若有去除相同元素的集合入队列,并进行标记;否则直接跳过垓步。然后将当前节点的相邻元素入队(如果还未搜索过)
  3. 当搜索到最后一个元素时直接返回当前的操作次数即可,BFS 保证了第一次搜到的就是最快的
public int minJumps(int[] arr) {
        // 存相同元素集合的哈希表
        Map<Integer, List<Integer>> idxOfSame = new HashMap<>();
        int n = arr.length;
        // 标记搜索过的节点
        boolean[] vis = new boolean[n];
        // 哈希表的初始化
        // 即将元素值相同的元素放入一个集合中,再放入哈希表
        for (int i = 0; i < n; i++) {
            idxOfSame.putIfAbsent(arr[i], new ArrayList<>());
            idxOfSame.get(arr[i]).add(i);
        }
        Queue<int[]> queue = new ArrayDeque<>();
        // 放入开始节点并标记
        queue.offer(new int[]{0, 0});
        vis[0] = true;
        // BFS
        while (!queue.isEmpty()) {
            // 取出节点
            int[] pair = queue.poll();
            // 当前遍历节点对应的索引
            int idx = pair[0];
            // 搜索到当前节点的操作数
            int step = pair[1];
            // 如果搜索到最后一个元素,直接退出
            if (idx == n - 1) {
                return step;
            }
            step++;
            // 判断当前节点值对应的集合是否在哈希表中
            if (idxOfSame.containsKey(arr[idx])) {
                // 取出集合
                List<Integer> list = idxOfSame.get(arr[idx]);
                int size = list.size();
                // 将集合对应的元素全部入队
                for (int i = 0; i < size; i++) {
                    int next = list.get(i);
                    if (!vis[next]) {
                        vis[next] = true;
                        queue.offer(new int[]{next, step});
                    }
                }
                // 从哈希表中去掉该集合,剪枝
                idxOfSame.remove(arr[idx]);
            }
            // 放入节点的相邻元素
            if (idx + 1 < n && !vis[idx + 1]) {
                vis[idx + 1] = true;
                queue.offer(new int[]{idx + 1, step});
            }
            if (idx - 1 >= 0 && !vis[idx - 1]) {
                vis[idx - 1] = true;
                queue.offer(new int[]{idx - 1, step});
            }
        }
        // 如果 BFS 未找到最后一个元素,那么搜索失败
        return -1;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值