【每日一题见微知著】Hash表+BFS—— 跳跃游戏 IV-Hard(今天这个难度对了)

⭐️寒假新坑——代码之狐的每日做题笔记

1345. 跳跃游戏 IV-Hard

题目描述:

给你一个整数数组 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 为数组的最后一个元素的下标。

解题思路:

BFS(广度优先搜索):处理每步到达的节点,添加其下一步能够到达的未到达过的节点(由上述规则)

Hash表:预处理相同节点,记录相同节点的下标

细节:处理完之后清除能够到达的节点节约历遍时间——测试用例存在一个全是7,只有最后节点为11,由此我加入

//这里清楚该相同数字的下标队列,因为已经访问完(不然会超时)
                    list.clear();

代码实现(空间应该还可以优化):

class Solution {
    public int minJumps(int[] arr) {
        int l=arr.length;
        
        //保存每一个数字的多个下标,方便查询跳转
        Map<Integer,List<Integer>> map=new HashMap<>();
        //记录是否访问的数组,false表示未访问
        boolean[] visited=new boolean[l];

        //初始化统计,记录相同数字的下标,用《数字-下标链表》表示
        for(int i=0;i<l;i++){
            int mid=arr[i];
            if(map.get(mid)==null){
                List<Integer> list=new ArrayList<>();
                list.add(i);
                map.put(mid,list);
            }
            else{
                map.get(mid).add(i);
            }
        }

        //每次使用一个队列保存下一步能够到达的下标
        //使用两个队列方便计算步骤
        List<Integer> q1=new ArrayList<>();
        List<Integer> q2=new ArrayList<>();

        //初始点0
        q1.add(0);
        visited[0]=true;
        
        int step=0;

        if(l-1==0){
            return 0;
        }

        while(true){
            if(q1.size()!=0){
                //q中保存当前步到达的点,历遍将下一步到达的点放入另一个q
                for(int cur:q1){

                    //下标+1
                    if(cur+1<l&&!visited[cur+1]){
                        //判断是否是目标
                        if(cur+1==l-1){
                            return step+1;
                        }
                        q2.add(cur+1);
                        visited[cur+1]=true;
                    }

                    //下标-1
                    if(cur-1>0&&!visited[cur-1]){
                        //不可能为目标
                        q2.add(cur-1);
                        visited[cur-1]=true;
                    }

                    //相同数字跳转
                    List<Integer> list=map.get(arr[cur]);
                    for(int next:list){
                        if(next==l-1){
                            return step+1;
                        }
                        if(!visited[next]){
                            q2.add(next);
                            visited[next]=true;
                        }
                    }
                    //这里清楚该相同数字的下标队列,因为已经访问完(不然会超时)
                    list.clear();
                }
                q1.clear();
            }
            else{
                //同上
                for(int cur:q2){

                    if(cur==l-1){
                        return step;
                    }

                    if(cur+1<l&&!visited[cur+1]){
                        if(cur+1==l-1){
                            return step+1;
                        }
                        q1.add(cur+1);
                        visited[cur+1]=true;
                    }

                    if(cur-1>0&&!visited[cur-1]){
                        q1.add(cur-1);
                        visited[cur-1]=true;
                    }

                    List<Integer> list=map.get(arr[cur]);
                    for(int next:list){
                        if(next==l-1){
                            return step+1;
                        }
                        if(!visited[next]){
                            q1.add(next);
                            visited[next]=true;
                        }
                    }
                    list.clear();
                }
                q2.clear();
            }
            //步骤+1
            step++;
        }
    }
}

结尾

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

⭐️关注作者,带你刷题,从简单的算法题了解最常用的算法技能(寒假每日一题)
⭐️关注作者刷题——简单到进阶,让你不知不觉成为无情的刷题机器,有问题请私信

上一篇:JZ12 矩阵中的路径


下一篇:Leetcode---3.BFS篇