JAVA练习33-跳跃游戏 IV

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

分析:

方法1:BFS + 哈希表

该游戏在跳跃的方式中有向左右跳和同数跳的方式,由于求跳的最小次数,所以很容易让人想到广度优先搜索(BFS),定义一个队列代表一层,一层遍历完后,将该层入栈,再将下一层的索引入栈,每一层代表跳的次数,如果跳到底,就返回该层数。

这时候为了避免多次跳跃,我们可以定义一个 HashSet 用来储存跳过的位置,如果重复就不跳。

关于同数跳跃,为避免多次操作,可以定义 HashMap 来存储每个数的索引,因为索引可以不止一个,值可以用 List 来存储,这个数的索引入栈后就将该数删除,避免造成内存浪费。

时间复杂度:O(n+e)
空间复杂度:O(n)   

class Solution {
    public int minJumps(int[] arr) {
        //数组
        int len = arr.length;
        //存储对应数字索引
        Map<Integer, List<Integer>> map = new HashMap<>();
        for(int i = len-1; i >= 0; i--){
            List<Integer> list = map.getOrDefault(arr[i], new ArrayList<>());
            list.add(i);
            map.put(arr[i], list);
        }
        //定义队列以便进行广度遍历
        Deque<Integer> queue = new ArrayDeque<>();
        //定义最小值
        int min = 0;
        //将首索引入队列
        queue.add(0);
        //记录重复索引
        HashSet<Integer> set = new HashSet<>();
        //到头停止循环
        while(true){
            int size = queue.size();
            while(size > 0){
                size--;
                int i = queue.pollFirst();
                //去重,防止重复操作
                if(set.contains(i)){
                    continue;
                }
                set.add(i);
                //到头了,终止循环
                if(i == len - 1){
                    return min;
                }
                //入栈左边
                if(i - 1 > 0){
                    queue.offerLast(i - 1);
                }
                //入栈右边
                if(i + 1 < len){
                    queue.offerLast(i + 1);
                }
                //入栈相容值的索引
                List<Integer> list = map.getOrDefault(arr[i], new ArrayList<>());
                for(int l: list){
                    queue.offerLast(l);
                }
                map.remove(arr[i]);
            }
            min++;
        }
    }
}

方法2:BFS+数组

由 方法1 的代码可以看出,在每一层都要用一次 while 循环来进行出栈入栈操作,在空间和时间上会造成一定的浪费,那么有没有一种方法可以不用 while 循环也可以达到相应操作的目的呢?想想之所以用 while ,是因为保证那一层的数组都出栈完,好记录跳跃的次数,既然如此,我们是不是就可以将 HashSet 替换成数组,然后数组的索引代表遍历对象数组的索引,利用数组来存储索引对应跳跃的次数,每一次遍历只要将数组的值取出来就可以了。

时间复杂度:O(n)
空间复杂度:O(n)   

class Solution {
    public int minJumps(int[] arr) {
        //数组
        int len = arr.length;
        //存储对应数字索引
        Map<Integer, List<Integer>> map = new HashMap<>();
        for(int i = len-1; i >= 0; i--){
            List<Integer> list = map.getOrDefault(arr[i], new ArrayList<>());
            list.add(i);
            map.put(arr[i], list);
        }
        //定义队列以便进行广度遍历
        Deque<Integer> queue = new ArrayDeque<>();
        //将首索引入队列
        queue.add(0);
        //记录每个索引遍历的层数
        int[] steps = new int[len];
        //到头停止循环
        while(true){
            int i = queue.pollFirst(), step = steps[i];
            //到头了,终止循环
            if(i == len - 1){
                return step;
            }
            step++;
            //入栈左边
            if(i - 1 > 0 && steps[i - 1] == 0){
                steps[i - 1] = step;
                queue.offerLast(i - 1);
            }
            //入栈右边
            if(i + 1 < len && steps[i + 1] == 0){
                steps[i + 1] = step;
                queue.offerLast(i + 1);
            }
            //入栈相容值的索引
            List<Integer> list = map.getOrDefault(arr[i], new ArrayList<>());
            for(int l: list){
                if(steps[l] == 0){
                    steps[l] = step;
                    queue.offerLast(l);
                }
            }
            map.remove(arr[i]);
        }
    }
}

题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game-iv

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

什巳

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值