java数据结构与算法刷题-----LeetCode1091. 二进制矩阵中的最短路径

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

文章目录

    • 广度优先+双分裂蛇

在这里插入图片描述
在这里插入图片描述

广度优先+双分裂蛇

双分裂蛇:是求二维表中从起点到终点的经典思路(也是求无权图的最短路径问题的经典解法)。创建两条分裂蛇,分别从起点和终点出发,两者相遇,则找到一条路径。时间复杂度理论上和单分裂蛇一样,但实际效率双分裂蛇更高。

  1. 分裂蛇的意思是:如果遇到分叉路,分裂蛇A可以分裂成对应数量的蛇,然后分头行动。
  2. 为什么双分裂蛇更快?因为只有一条蛇时,最坏情况下所有结点都走一遍才能找到最短路径
  3. 双分裂蛇,无论分裂多少,肯定是最短路径上的两条蛇最先相遇。所以两条蛇初次相遇的路径,就是最短路径。而不用像单分裂蛇那样,很有可能将所有路走一遍再比较才能知道哪条路最短

简单来说,单分裂蛇,它需要走的步数更多,因为它要自己从起点走到终点,因此分裂的蛇也就越多,访问的结点也就越多。
而双分裂蛇,两条蛇走的步数都是单分裂蛇的一半。所以两条蛇分裂的蛇会很少。访问的结点就少

举个例子,一张可以无限对折的0.0002米厚的纸,对折40次左右可以到月球,40次正好就是219902公里。而对折40次的一半左右,比如23次只有1.677公里。此时我搞两张纸各对折40次的一半,加起来是1.677+1.677 = 3.3公里左右

可见,219902公里是一张纸对折40次的结果3.3公里左右是两张纸对折40次一半20次左右的结果. 而回到分裂蛇的例子。一条蛇分裂40次,和两条蛇各分裂20次。谁访问的结点更少呢?

因此理论上,最坏情况下双分裂蛇和单分裂蛇都是n^2的时间复杂度,也就是每个结点访问两次,但是实际上,找最短路径,就和一张纸对折40次和两张纸对折20次的区别是一样的,只要路径足够长,双分裂蛇访问的结点个数,和单分裂蛇访问的结点个数根本不是一个量级,就像一张纸对折40次上月球,两张纸对折20次加起来走不出一个小区是一个道理。双分裂蛇的效率是比单分裂蛇高的。

但是无论单分裂蛇还是双分裂蛇,找最短路径,都满足:初次相遇的蛇所在路径为最短路径。

也就是,就算是单分裂蛇,也不需要所有路径走一遍统计路径长度,才能找出最短的
因为最短路径上的蛇一定会先最先到达。(前提是所有蛇的速度一样,都是大家一起一步一步走)

解题思路:时间复杂度O( n 2 n^2 n2),空间复杂度O( n 2 n^2 n2)
  1. 创建两个队列A和B,当做分裂蛇,分别从起点[0][0]和终点[n-1][n-1]出发,将两个结点分别入各自的队列
  2. A队列先走一步,情况允许就分裂。新分裂出的蛇额外走
  1. 一步的含义是,我可以向8个方向走,只要能走就走。
  2. 分裂:如果多个方向都满足条件,则进行分裂,让分裂的蛇到达指定地点(一步),然后将分裂的蛇全部入队列
  3. 但是新入队列的蛇,不可以继续处理,因为它们已经走了一步了
  1. 如果两个队列没有相遇,B队列也走一步,情况允许就分裂,新分裂的不走
  2. 直到两个队列中有蛇相遇,就结束程序。因为双分裂蛇的特点就是,最先相遇的两条蛇所在路径为最短路径
代码:会给出双分裂蛇和单分裂蛇的两版代码,除了蛇的数量不一样,剩余代码全部一样,可以很明显的看见,双分裂蛇的效率高多了,比单分裂蛇效率高了40%
  1. 双分裂蛇版本用时6ms
    在这里插入图片描述
class Solution {
    final static int[] dx = {1, 1, 1, 0, 0, -1, -1, -1};//右下,下,左下,右,左,右上,上,左上
    final static int[] dy = {1, 0, -1, 1, -1, 1, 0, -1};//右下,下,左下,右,左,右上,上,左上
    final static int SIGN_A = 2;//A队列走过的路的标识
    final static int SIGN_B = 3;//B队列走过的路的标识
    class Node {//队列中的结点,保存x和y坐标
        int x, y;
        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public int shortestPathBinaryMatrix(int[][] grid) {
        int n = grid.length;
        if(grid[0][0] == 1 || grid[n-1][n-1] == 1) return -1;
        else if(grid[0][0] == 0 && n == 1) return 1;

        int steps = 2;//走了多少步,两个队列(贪吃蛇)一起算
        //头尾队列,一个从头走,一个从尾巴走,两个队列相遇,就是一个答案
        Queue<Node> headQue = new LinkedList<Node>();
        Queue<Node> tailQue = new LinkedList<Node>();
        headQue.offer(new Node(0, 0));
        tailQue.offer(new Node(n-1, n-1));

        grid[0][0] = SIGN_A;
        grid[n-1][n-1] = SIGN_B;
        //两个队列一起走
        while(!headQue.isEmpty() && !tailQue.isEmpty()) {
            boolean encounter = nextStep(grid, headQue, SIGN_A);//A队列走一步,是否相遇B队列
            if(encounter) return steps;//如果相遇,则返回步数
            //没有相遇,则A队列步数+1
            steps++;
            //B队列走一步,是否相遇A队列
            encounter = nextStep(grid, tailQue, SIGN_B);
            if(encounter) return steps;
            steps++;
        }
        return -1;//如果一直没有相遇就返回-1
    }
    //走一步
    private boolean nextStep(int [][]grid, Queue<Node> que, int sign) {
        int n = grid.length;
        int size = que.size();
        while((size--) > 0) {//如果当前队列有结点(无论多少个),那么这些结点只走一步,不多走,也就是这些结点走了一步后,过程中新添加的结点,本次不考虑
            Node cur = que.poll();//出队列当前结点
            int x = cur.x, y = cur.y;//获取其坐标
            for(int i = 0; i < 8; ++i) {//8个方向按右下,下,左下,右,左,右上,上,左上的顺序走一下
                int nx = x + dx[i];
                int ny = y + dy[i];
                //如果下标越界,或者要走的这一方向==1(此路不通),或者要走的这一方向当前队列已经走过了grid[nx][ny] == sign,就跳过
                if(nx < 0 || nx >= n || ny < 0 || ny >= n || grid[nx][ny] == 1 || grid[nx][ny] == sign) continue;
                // 如果要走的方向遇到了另一个队列,则说明相遇
                if(grid[nx][ny] != 0) return true;//返回true
                //如果没有相遇,向当前方向走一步
                grid[nx][ny] = sign;
                que.add(new Node(nx, ny));//添加到队列继续
            }
        }
        return false;
    }
}
  1. 单分裂蛇版本,用时10ms
    在这里插入图片描述
class Solution {
    public int shortestPathBinaryMatrix(int[][] grid) {
        if(grid[0][0] != 0)return -1;
        if(grid.length == 1){
            if(grid[0][0] == 0) return 1;
            else return -1;
        }
        int[] dx = {-1, -1, -1, 0,  0, 1, 1, 1};
        int[] dy = {-1, 0, 1, -1, 1, -1, 0,1};
        int n = grid.length;
        // 记录坐标
        Queue<int[]> queue = new LinkedList();//单分裂蛇
        queue.offer(new int[]{0,0});//从起点开始
        grid[0][0] = 1;//走过的就标志为1
        int length = 0;//路径长度
        loop:while(queue.size() > 0){//如果还有分裂蛇存在
            int size = queue.size();//获取当前分裂蛇,这些分裂蛇可以进行分裂,然后走一步
            ++length;//走一步+1个路径长度
            while((size--) > 0){//只有当前分裂蛇可以走一步,多条路可走就分裂,新的分裂蛇不可以走,如果使用queue.size()会将新的分裂蛇也处理了
                int[] pos = queue.poll();//依次获取这些现在存在的分裂蛇
                for(int i =0; i < 8; i++){//从8个方向走
                    int x = pos[0] + dx[i];
                    int y = pos[1] + dy[i];
                    //如果这个方向可以走,并且没有分裂蛇走过
                    if(x >=0 && y >= 0 && x < grid.length && y < grid.length && grid[x][y] == 0){
                        queue.offer(new int[]{x,y});//就分裂一条蛇过去,这条分裂后新进入队列的蛇,本次不可以再处理
                        grid[x][y] = length +1;//将此结点标志为已到达过,赋值为:路径长度+1
                        //这里很重要,终点一定是最短路径的蛇先到,此时它会将这个结点标志为已到访过
                        //后面在较长路径的蛇,不会覆盖这个值
                        //如果当前分裂蛇是第一个到终点的,则他就是最短路径上的蛇
                        if(x == grid.length-1 && y == grid.length-1) break loop;//跳出整个循环,不继续处理任何蛇
                    }
                }
            }
        }
        return grid[n-1][n-1] <2 ? -1 : grid[n-1][n-1];//返回到终点的最短路径长度
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/503755.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HCIA-Datacom实验_04_实验二:IPv4编址及IPv4路由基础实验

一、拓扑 二、改名 R1 R2 R3 三、配置接口IP R1 R2 R3 四、查看路由表 此时每台设备上会有两条直连路由 R1 R2 R3 五、ping测试 R1pingR2接口 R1pingR3接口 R2pingR1接口 R2pingR3接口 R3pingR1接口 R3pingR2接口 六、配置LoopBack地址 R1 R2 R3 七、写路由 R1到R2的Loo…

吴恩达2022机器学习专项课程(一) 4.1 梯度下降

问题预览 梯度下降算法的作用是&#xff1f;梯度下降的过程&#xff1f;梯度下降和最小化成本函数的联系&#xff1f;所有的成本函数都是一个形状吗&#xff1f;在非凸形状中&#xff0c;梯度下降的更新过程是&#xff1f;在非凸形状中&#xff0c;不同的初值对最小化成本函数…

C++:数据类型—布尔(12)

布尔类型代表就是真和假&#xff08;bool&#xff09; 真就是1&#xff08;true&#xff09; 假就是0&#xff08;false&#xff09; 也可以任务非0即为真 bool 直占用1个字节大小 语法&#xff1a;bool 变量名 (true | false&#xff09; 提示&#xff1a;bool在后期判断也是…

扫描体的概念、应用及实现方法

扫描体&#xff08;Swept Volume&#xff0c;简称SV&#xff09;&#xff0c;从广义上来说&#xff0c;是指以任一对象&#xff08;几何模型或曲面集&#xff09;为扫描母体&#xff0c;沿着空间任一路径&#xff08;扫描路径&#xff09;&#xff0c;以某种方式运动最终产生的…

软考高级架构师:安全模型概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

TC16-161T+ 音频 信号变压器 RF Transformers 600kHz-160MHz 射频集成电路 Mini-Circuits

Mini-Circuits是一家全球领先的射频、微波和毫米波元器件及子系统制造商。TC16-161T是Mini-Circuits出产的一款射频IC&#xff08;射频集成电路&#xff09;&#xff0c;具有平衡-不平衡转换器功用。制造商: Mini-Circuits 产品品种: 音频变压器/信号变压器 RoHS…

一篇文章带你了解Java网络原理

网络发展史 独立模式 独立模式:计算机之间相互独立; ⽹络互连 随着时代的发展&#xff0c;越来越需要计算机之间互相通信&#xff0c;共享软件和数据&#xff0c;即以多个计算机协同⼯作来完成业务&#xff0c;就有了⽹络互连。 ⽹络互连&#xff1a;将多台计算机连接在⼀起…

初步了解JavaSE

目录 前言&#xff1a; 一、Java SE主要包含模块&#xff1a; 二、JavaSE的环境搭建 三、JavaSE简单入门 1&#xff09;文件名称不对&#xff0c;如果有一个叫 helloworld.java&#xff0c;但是class命名为HelloWord. 2&#xff09;如果希望我们文件名称和类名不一致&…

习题2-5 求平方根序列前N项和

本题要求编写程序&#xff0c;计算平方根序列 的前N项之和。可包含头文件math.h&#xff0c;并调用sqrt函数求平方根。 输入格式: 输入在一行中给出一个正整数N。 输出格式: 在一行中按照“sum S”的格式输出部分和的值S&#xff0c;精确到小数点后两位。题目保证计算结果不…

docker 共享网络的方式实现容器互联

docker 共享网络的方式实现容器互联 本文以nacos连接mysql为例 前提已经在mysql容器中初始化好nacos数据库&#xff0c;库名nacos 创建一个共享网络 docker network create --driver bridge \ --subnt 192.168.0.0/24 \ --gateway 192.168.0.1 mynet此处可以不指定网络模式、…

【QT+QGIS跨平台编译】045:【netcdf3+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、NetCDF3介绍二、文件下载三、文件分析四、pro文件五、编译实践一、NetCDF3介绍 NetCDF(Network Common Data Form)是一种用于存储科学数据的文件格式和库。NetCDF3 是 NetCDF 的旧版本,通常指的是 NetCDF 版本 3.x。 以下是 NetCDF3 的一些特…

速腾聚创上市后首份财报:冲击年销百万台,押注人形机器人

作者 |老缅 编辑 |德新 港股「激光雷达第一股」速腾聚创&#xff0c;交出了上市后的首份业绩报告。 3月27日&#xff0c;速腾聚创发布了2023年度财报。 报告期内&#xff0c;公司迎来高速的业务增长——2023年总收入达到人民币11.2亿元&#xff0c;同比增长达到111.2%。这主…

算法学习——LeetCode力扣动态规划篇9

算法学习——LeetCode力扣动态规划篇9 1035. 不相交的线 1035. 不相交的线 - 力扣&#xff08;LeetCode&#xff09; 描述 在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#x…

CCPC2020 - 秦皇岛 - G. Good Number (数学)

亚历克斯喜欢数字。 亚历克斯认为&#xff0c;正整数 x x x 是好数&#xff0c;当且仅当 ⌊ x k ⌋ \lfloor \sqrt[k]{x} \rfloor ⌊kx ​⌋ 整除 x x x 。 你能告诉他不超过 n n n 的正整数的个数吗&#xff1f; 输入 输入的第一行给出了测试用例的数量 T ( 1 ≤ T ≤…

Pytorch 下载失败原因

错误信息&#xff1a; ERROR: Could not find a version that satisfies the requirement torch (from versions: none) ERROR: No matching distribution found for torch 解决方案&#xff1a; 在官网看到&#xff0c;它需要python3.8-3.11的环境。过高和过低的版本都不…

python学习16:python中的布尔类型和条件语句的学习

python中的布尔类型和条件语句的学习 1.布尔&#xff08;bool&#xff09;类型的定义&#xff1a; 布尔类型的字面量&#xff1a;True表示真&#xff08;是、肯定&#xff09; False表示假&#xff08;否、否定&#xff09; True本质上是一个数字记作1&#xff0c;False记作0 …

208基于matlab的多目标遗传算法的无人机航路规划

基于matlab的多目标遗传算法的无人机航路规划。在三维航路中进行航路代价估计&#xff0c;综合考虑路径长度、隐蔽性、危险度&#xff0c;规划出最优路径。输出3D规划路径。程序已调通&#xff0c;可直接运行。 208 多目标遗传算法 无人机航路规划 - 小红书 (xiaohongshu.com)

力扣---网络延迟时间---迪杰斯特拉,弗洛伊德floyd

首先推荐博客&#xff1a;图论最短路径专题&#xff08;力扣743、5888&#xff09;_力扣 最短路径-CSDN博客 迪杰斯特拉算法&#xff1a; 太久没有做图论的题了&#xff0c;&#xff0c;临时抱佛脚。。 这道题可以转化为max{点x到点k的距离}。因为带权图&#xff08;权值为正…

手机投屏到windows11电脑

1 安装无线投影组件 2 电脑端打开允许其他设备投影的开关 3 手机找到投屏选项 4 手机搜索可用设备连接即可 这里的官方文档给的不太好,给了一些让人眼花撩乱的信息,以下是经过整合的有效信息

Linux 给网卡配置ip

ip addr | grep eth9 ifconfig eth9 10.0.0.2 netmask 255.255.255.0 up