【算法】【优选算法】BFS 解决边权相同最短路问题

【算法】【优选算法】BFS 解决边权相同最短路问题

目录

一、1926.迷宫中离⼊⼝最近的出⼝

题目链接:1926.迷宫中离⼊⼝最近的出⼝

题目描述:

题目解析:

  • 给我们一个字符数组 + 表示墙,. 表示路。
  • 求给我们的起始坐标,上下左右走到边界最短的距离。
  • 没路出去返回-1,刚开始的起点不算距离。

解题思路:

  • 使用层序遍历,从给我们的起点开始,
  • 每一次都将队列中的元素全部取出,相当于进了一步。
  • 直到没路可走,或者走到边界。
  • 使用一个相同大小的标记数组,将走过的路和墙标记。标记过的下标不入队。
    解题代码:
时间复杂度:O(M*N) 空间复杂度:O(M*N)classSolution{int[] dx ={1,-1,0,0};int[] dy ={0,0,1,-1};boolean[][] flag;int m, n;publicintnearestExit(char[][] maze,int[] entrance){ m = maze.length; n = maze[0].length; flag =newboolean[m][n];for(int i =0; i < m; i++){for(int j =0; j < n; j++){if(maze[i][j]=='+'){ flag[i][j]=true;}}}Queue<int[]> queue =newLinkedList<>(); queue.add(newint[]{entrance[0], entrance[1]}); flag[entrance[0]][entrance[1]]=true;int length =0;while(!queue.isEmpty()){ length++;int size = queue.size();//将这一层元素出完for(int i =0; i < size; i++){int[] arr = queue.poll();//层序遍历入队for(int j =0; j <4; j++){int x = dx[j]+ arr[0];int y = dy[j]+ arr[1];if( x >=0&& x < m && y >=0&& y < n && maze[x][y]=='.'&&!flag[x][y]){//结束条件if(x ==0|| x == m -1|| y ==0|| y == n -1){return length;}System.out.println(x +" "+y +" 入队"+length); queue.add(newint[]{x,y}); flag[x][y]=true;}}}}return-1;}}

二、433. 最⼩基因变化

题目链接:433. 最⼩基因变化

题目描述:

题目解析:

  • 给我们一个起始字符串start和最终字符串end,长度固定为8
  • 起始字符串每一次可以变化一个字符,并且变化后的字符串必须属于bank字符串数组中的值
  • 求最短从start变成end的次数。

解题思路:

  • 我们将起始的字符串中的字符,每一个字符都有四个突变选择,层序遍历每一种突变的可能,符合条件(包含在基因库,突变过后是全新未突变过得到的),直到与最后end相同为止。
  • 我们需要使用两个hash表,一个记录每个符合条件的突变结果,一个记录基因库好实行对比。
  • 我们顺序遍历起始字符串,每一次队列中的元素,相当于突变一次可以达到的结果,每次将队列中的元素出完,出一次就相当于进行一次实际突变。
  • 当最终的end字符串不在基因库,或者进行突变完了(队列空了),还没有找到结果,就返回-1。
    解题代码:
//时间复杂度:O(N)//空间复杂度:O(N)classSolution{publicintminMutation(String startGene,String endGene,String[] bank){Set<String> flag =newHashSet<>();//标记改变过的基因Set<String> hash =newHashSet<>();//记录基因库bank元素for(String s : bank) hash.add(s);System.out.println(hash.toString());//end基因无效if(!hash.contains(endGene))return-1;Queue<String> queue =newLinkedList<>(); queue.add(startGene); flag.add(startGene);int length =0;char[] change ={'A','C','G','T'};while(!queue.isEmpty()){int size = queue.size(); length++;//层序遍历for(int i =0; i < size; i++){String t = queue.poll();//遍历字符串的字符,一一突变for(int j =0; j <8; j++){char[] tmp = t.toCharArray();//突变for(int k =0; k <4; k++){ tmp[j]= change[k];String next =newString(tmp);//入队条件if(hash.contains(next)&&!flag.contains(next)){ queue.add(next); flag.add(next);}//结束条件if(next.equals(endGene))return length;}}}}return-1;}}

三、127. 单词接⻰

题目链接:127. 单词接⻰

题目描述:

题目解析:

  • 给我们一个起始单词beginWord和一个结束单词endWord,和一个字典wordList
  • 我们一次变化一个字母,使beginWord 变到 endWord,并且每一次变化后单词必须在 wordList 中

解题思路:

  • 跟上一题一模一样,只不过变化是26个小写字母
    解题代码:
//时间复杂度:O(N)//空间复杂度:O(N)classSolution{publicintladderLength(String beginWord,String endWord,List<String> wordList){Set<String> hash =newHashSet<>();for(String s : wordList) hash.add(s);//endWord不在字典if(!hash.contains(endWord))return0;//标记表Set<String> flag =newHashSet<>(); flag.add(beginWord);//队列Queue<String> queue =newLinkedList<>(); queue.add(beginWord);int ret =1;while(!queue.isEmpty()){int size = queue.size(); ret++;for(int k =0; k < size; k++){String s = queue.poll();for(int i =0; i < s.length(); i++){char[] tmp = s.toCharArray();//26个字母for(char j ='a'; j <='z'; j++){ tmp[i]= j;//入队条件String string =newString(tmp);if(hash.contains(string)&&!flag.contains(string)){System.out.println(string); queue.add(string); flag.add(string);}//结束条件if(string.equals(endWord))return ret;}}}}return0;}}

四、675. 为⾼尔夫⽐赛砍树

题目链接:675. 为⾼尔夫⽐赛砍树

题目描述:

题目解析:

  • 给我们一个数组,让我们从根据数组值的大小依次砍树,0代表墙,1代表地面
  • 让我们计算一次砍树,我们需要走的最短路径

解题思路:

  • 我们先将怎么砍树记录出来,将数组中大于0的值,按数组值从小到大排序,将他们的下标存入一个数组中;
  • 然后该数组中每一个前面元素(起始)到后元素(结尾)都相当于求一次最短路径
  • 注意第一次是坐标(0,0)起始,因此当第二个坐标是代表地面的时候,我们就要跳过这一次。例如:[[1,2,3],[0,0,4],[7,6,5]]这个数组。

解题代码:

//时间复杂度:O(N)//空间复杂度:O(N)classSolution{int[] dx ={1,-1,0,0};int[] dy ={0,0,1,-1};int m, n;publicintcutOffTree(List<List<Integer>> forest){ m = forest.size(); n = forest.get(0).size();//找出砍树的顺序,根据树的大小排序List<int[]> trees =newArrayList<>();for(int i =0; i < m; i++){for(int j =0; j < n; j++){if(forest.get(i).get(j)>0) trees.add(newint[]{i,j});}}//排序Collections.sort(trees,(a,b)->{return forest.get(a[0]).get(a[1])- forest.get(b[0]).get(b[1]);});int ret =0;int beginX =0;int beginY =0;//标记数组for(int[] tree : trees){int endX = tree[0];int endY = tree[1];int tep =0;//下一步是地面if(forest.get(endX).get(endY)==1)continue; tep =bfs(forest,beginX,beginY,endX,endY);if(tep ==-1)return-1; ret += tep; beginX = endX; beginY = endY;}return ret;}//ab代表下一棵砍的坐标,xy表示当前的位置publicintbfs(List<List<Integer>> forest,int beginX,int beginY,int endX,int endY){//当前就是要砍的树if((beginX == endX && beginY == endY))return0;//标记数组,走过的路boolean[][] flag =newboolean[m][n];int tep =0;Queue<int[]> queue =newLinkedList<>(); queue.add(newint[]{beginX,beginY}); flag[beginX][beginY]=true;//bfswhile(!queue.isEmpty()){int size = queue.size(); tep++;while(size --!=0){int[] arr = queue.poll();int nx,ny;for(int i =0; i <4; i++){ nx = arr[0]+ dx[i]; ny = arr[1]+ dy[i];//入队条件if(nx >=0&& nx < m && ny >=0&& ny < n &&!flag[nx][ny]&& forest.get(nx).get(ny)!=0){ queue.add(newint[]{nx,ny}); flag[nx][ny]=true;//到了if(nx == endX && ny == endY)return tep;}}}}return-1;}}

Read more

Linux:初始网络(上)

之前我们学习了linux的系统部分,从现在开始,我们将进入linux网络部分的学习,在正式开始学习网络之前,我们需要先了解一下什么网络,他是源自什么的,怎么发展的,以及协议的浅层意思,话不多说,现在开始 ⽹络基础概念 ⽹络发展 独⽴模式: 计算机之间相互独⽴ 在以前,计算机都是独立的,所以为了合作,只能A完成A的部分,然后将类似磁盘的存储数据的东西交给B,B再完成B的部分,然后教给C,C完成自己的部分,可想而知,这样效率缓慢 ⽹络互联: 多台计算机连接在⼀起, 完成数据共享 为了解决这种事情,有人提议将ABC三台电脑连接到一个服务器上,这样A完成之后只需要把数据给服务器,B只需要拉下服务器的数据就可以,不需要人跑来跑去送数据,这就是网络互联 局域⽹LAN: 计算机数量更多了, 通过交换机和路由器连接在⼀起 越来越多计算机这样,于是为了更好的联系,出现了交换机连接 ⼴域⽹WAN: 将远隔千⾥的计算机都连在⼀起 当局域网多了,于是他们又互相链接,

By Ne0inhk
Linux 进程间通信之命名管道(FIFO):跨进程通信的实用方案

Linux 进程间通信之命名管道(FIFO):跨进程通信的实用方案

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 命名管道核心概念:什么是 FIFO? * 1.1 命名管道的定义 * 1.2 命名管道的核心特性 * 1.3 命名管道和匿名管道的区别与联系 * 二. 命名管道的创建方式 * 2.1 命令行创建(mkfifo 命令) * 2.2 代码创建(mkfifo 函数) * 三. 命名管道的打开规则(关键!) * 四. 命名管道实战案例 * 4.1 案例 1:命名管道实现文件拷贝 * 4.1.

By Ne0inhk
Flutter 组件 ansi_styles 的鸿蒙化适配实战 - 驾驭极致终端交互艺术、实现 OpenHarmony 开发链路、日志系统与控制台的工业级色彩分级方案

Flutter 组件 ansi_styles 的鸿蒙化适配实战 - 驾驭极致终端交互艺术、实现 OpenHarmony 开发链路、日志系统与控制台的工业级色彩分级方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 ansi_styles 的鸿蒙化适配实战 - 驾驭极致终端交互艺术、实现 OpenHarmony 开发链路、日志系统与控制台的工业级色彩分级方案 前言 在鸿蒙(OpenHarmony)生态的底座开发、高性能服务端侧逻辑构建、或者是对命令行交互(CLI)有极其严苛要求的自动化工程流水线中。“终端日志的可视化分级与视觉重心引导维度”是衡量整个底层调试链路效能的最终质量门禁。面对包含数万行内核日志、海量网络请求报文、甚至是 0308 批次重型打包过程产生的满屏文字流。如果仅仅依靠终端中苍白的一串 White 和 Black 或者是毫无温标感的 txt 控制台。不仅会导致在定位历史回退(Regression)时让开发工程师如同在字符废墟中盲人摸象。更会因为缺乏大局观的报错优先级呈现。令技术高层在跨终端指挥调度时陷入严重的信息盲区。 我们需要一种“色彩生动、警示分明”的终端资产汇报艺术。 ansi_styles 是一套专注于无缝整合全球公认顶级

By Ne0inhk
Flutter 组件 vietqr_gen 适配鸿蒙 HarmonyOS 实战:标准聚合支付,构建金融级二维码生成与跨境支付治理架构

Flutter 组件 vietqr_gen 适配鸿蒙 HarmonyOS 实战:标准聚合支付,构建金融级二维码生成与跨境支付治理架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 vietqr_gen 适配鸿蒙 HarmonyOS 实战:标准聚合支付,构建金融级二维码生成与跨境支付治理架构 前言 在鸿蒙(OpenHarmony)生态迈向全场景商业化、涉及跨境数字化金融、智能收银终端及分布式聚合支付的背景下,如何生成符合国际 EMVCo 标准且具备高可靠校验机制的支付二维码,已成为决定金融类应用“交易确定性”的核心环节。在鸿蒙设备这类强调内核级安全防护与高精度金融计算的环境下,如果应用依然依赖简单的字符串拼接来构造具有复杂 TLV(Tag-Length-Value)结构的支付密令,由于由于字节统计误差或 CRC 校验逻辑漏洞,极易由于由于扫码解析失败导致资金结算链路的中断。 我们需要一种能够自动化 TLV 封装、支持标准银行目录映射且具备高精度 CRC16 校验的金融级生成方案。 vietqr_gen 为 Flutter 开发者引入了标准化的聚合支付二维码生成协议。它不仅支持对收款账号、金额及备注的结构化打包,更

By Ne0inhk