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

news2024/11/24 16:57:33
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];//返回到终点的最短路径长度
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

上门家政按摩H5小程序源码

《服务器环境配置》 1、服务器环境&#xff1a;CentOS7 宝塔 Nginx php 2、环境&#xff1a;PHP7.2 MySQL5.6 3、安装扩展&#xff1a;fileinfo、redis 《程序安装配置》 1、新建站点及数据库&#xff0c;然后申请创建SSL证书&#xff0c;配置到站点&#xff0c;开启强…

LeetCode Python - 84. 柱状图中最大的矩形

目录 题目描述解法方法一方法二 运行结果方法一方法二 题目描述 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights …

“崖山数据库杯”深圳大学程序设计竞赛(正式赛)M题 一图秒

“崖山数据库杯”深圳大学程序设计竞赛&#xff08;正式赛&#xff09;_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com) —————— 可以去牛客看题解&#xff1a; 题解 | #暂时没想法#_牛客博客 (nowcoder.net) —————— 上面的就是题解了。…

CKS之安全沙箱运行容器:gVisor

目录 一、gVisor介绍 二、gVisor架构 三、gVisor使用前置条件 四、Docker中使用gVisor 五、containerd中使用gVisor 六、Kubernetes结合gVisor使用 一、gVisor介绍 gVisor是Google开源的一种容器沙箱技术&#xff0c;其设计初衷是在提供较高安全性的同时&#xff0c;尽量…

文本文件操作

大家好&#xff1a; 衷心希望各位点赞。 您的问题请留在评论区&#xff0c;我会及时回答。 文件操作 程序运行时&#xff0c;产生的数据都是临时数据&#xff0c;程序一旦运行结束都会被释放。通过文件可以将数据持久化。 C中对文件进行操作需要包含头文件<fstream> 文件…

语音识别:基于HMM

HMM语音识别的解码过程 从麦克风采集的输入音频波形被转换为固定尺寸的一组声学向量&#xff1a; 其中是维的语音特征向量&#xff08;例如MFCC&#xff09;。 解码器尝试去找到上述特征向量序列对应的单词&#xff08;word&#xff09;的序列&#xff1a; 单词序列的长度是。…

是德科技keysight N9000B 信号分析仪

181/2461/8938产品概述&#xff1a; 工程的内涵就是将各种创意有机地联系起来&#xff0c;并解决遇到的问题。 CXA 信号分析仪具有出色的实际性能&#xff0c;它是一款出类拔萃、经济高效的基本信号表征工具。 它的功能十分强大&#xff0c;为一般用途和教育行业的用户执行测试…

罗永浩直播阿里云服务器是哪款?ECS经济型e实例性能如何?

罗永浩直播卖阿里云&#xff0c;带货爆款云服务器ECS经济型e实例是什么&#xff1f;阿里云服务器ECS经济型e实例的使命是什么&#xff1f;一般来讲&#xff0c;学生、开发者和小微企业主要使用云服务器主要开展网站建设、开发测试和业务灾备、搭建小程序后端服务、Web应用、云上…

量化交易入门(三十三)BIAS指标实现和回测

接下来我们还是用苹果股票2020年1月1日到2023年12月30日的历史数据进行回测&#xff0c;看看这个指标的效果如何&#xff0c;具体回测结果如下&#xff1a; 策略运行结果及解读 执行的结果&#xff1a; Starting Portfolio Value: 100000.00 Final Portfolio Value: 186723.0…

git基本操作二(小白快速上手)

1、前言 接上篇我们接着来继续讲 2、.gitignore忽略文件 创建一个.gitignore文件&#xff0c;并将其置于项目的根目录下&#xff0c;Git将自动识别并根据该规则忽略相应的文件和目录。 # 忽略所有的 .log 文件 *.log# 但跟踪所有的 build.log 文件 !build.log# 忽略所有的 /lo…

Visual Studio 2022 中 Qt 开发环境的搭建

Visual Studio 2022 中 Qt 开发环境的搭建 Visual Studio 2022 中 Qt 开发环境的搭建 Visual Studio 2022 中 Qt 开发环境的搭建 点击扩展&#xff0c;并选择管理扩展。 搜索qt&#xff0c;下载并安装 Qt Visual Studio Tools。 安装完成后&#xff0c;点击扩展&#xff0c;会…

pytorch常用的模块函数汇总(1)

目录 torch&#xff1a;核心库&#xff0c;包含张量操作、数学函数等基本功能 torch.nn&#xff1a;神经网络模块&#xff0c;包括各种层、损失函数和优化器等 torch.optim&#xff1a;优化算法模块&#xff0c;提供了各种优化器&#xff0c;如随机梯度下降 (SGD)、Adam、RMS…

基于SpringBoot的“校园台球厅人员与设备管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“校园台球厅人员与设备管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 系统首页界面图…

信息工程大学第五届超越杯程序设计竞赛(同步赛)题解

比赛传送门 博客园传送门 c 模板框架 #pragma GCC optimize(3,"Ofast","inline") #include<bits/stdc.h> #define rep(i,a,b) for (int ia;i<b;i) #define per(i,a,b) for (int ia;i>b;--i) #define se second #define fi first #define e…

YOLOv8算法改进【NO.111】利用shift-wise conv对顶会提出EMO中的iRMB进行二次创新

前 言 YOLO算法改进系列出到这&#xff0c;很多朋友问改进如何选择是最佳的&#xff0c;下面我就根据个人多年的写作发文章以及指导发文章的经验来看&#xff0c;按照优先顺序进行排序讲解YOLO算法改进方法的顺序选择。具体有需求的同学可以私信我沟通&#xff1a; 首推…

Vue + .NetCore前后端分离,不一样的快速发开框架

摘要&#xff1a; 随着前端技术的快速发展&#xff0c;Vue.NetCore框架已成为前后端分离开发中的热门选择。本文将深入探讨Vue.NetCore前后端分离的快速开发框架&#xff0c;以及它如何助力开发人员提高效率、降低开发复杂度。文章将从基础功能、核心优势、适用范围、依赖环境等…

Qt for WebAssembly 环境搭建 - Windows新手入门

Qt for WebAssembly 环境搭建 - Windows新手入门 一、所需工具软件1、安装Python2、安装Git2.1 注册Github账号2.2 下载安装Git2.2.1配置Git&#xff1a;2.2.2 配置Git环境2.2.3解决gitgithub.com: Permission denied (publickey) 3 安装em编译器 二、Qt配置编译器三、参考链接…

wireshark 使用

wireshark介绍 wireshak可以抓取经过主机网卡的所有数据包&#xff08;包括虚拟机使用的虚拟网卡的数据包&#xff09;。 环境安装 安装wireshark: https://blog.csdn.net/Eoning/article/details/132141665 安装网络助手工具&#xff1a;https://soft.3dmgame.com/down/213…

【Java SE】深入理解static关键字

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1.static关键字1.1 static的概念1.2 static的作用1.3 static的用法1.3.1 static修饰成员变量1.3.2 static修饰…

记一次由gzip引起的nginx转发事故

故事背景 书接前几篇文章&#xff0c;仍然是交付甲方遇到的一个特殊诉求&#xff0c;从而引发了本期的事故。甲方的诉求是前端的请求过来&#xff0c;需要加密&#xff0c;但是要经过waf&#xff0c;必须要求是请求明文&#xff0c;那就要在waf和nginx之间做一个解密前置应用处…