图论基础算法/DFS+BFS+Trie树

news2024/12/23 8:15:38

八、图论

8.1深度优先搜索
  • 和树类似,只不过这里需要优化,因为是多对多,对访问的节点加上标记防止重复访问,(下面BFS的题目腐烂的橘子因为有权重值,也就判断是一次污染还是二次三次…污染,所以不能这么简单标记,不可以DFS)

  • 力扣200

    class Solution {
        public int numIslands(char[][] grid) {
            int res = 0;
            int row = grid.length;
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < grid[i].length; j++) {
                    if (grid[i][j] == '1') {
                        dfs(grid, i, j);
                        res++;
                    }
                }
            }
            return res;
        }
    
        public void dfs(char[][] grid, int x, int y) {
            if (x < 0 || y < 0 || y >= grid[0].length || x >= grid.length || grid[x][y] != '1') {
                return;
            }
            grid[x][y] = '2';
            dfs(grid, x, y - 1);
            dfs(grid, x, y + 1);
            dfs(grid, x - 1, y);
            dfs(grid, x + 1, y);
        }
    }
    

    就是对访问过的陆地变为2(碰到不会重复访问),然后进行DFS,如果是最后多条路径碰到水或者四周就说明就是一块岛屿。然后主循环继续寻找为1的陆地,然后进行dfs,循环往复

8.2广度优先搜素
8.2.1拓扑排序
  1. 首先初始化一个入度表(数组)、一个邻接表(二位数组)、一个队列(用来拓扑排序的构建)
  2. 遍历队列,删除首元素,根据首元素的删除,动态减少入度表的值(只需要更改,首元素指向的几条点,因为只改了这几个点的入度),直到遍历队列为空。
  • 注意拓扑排序使用于有向无环图,所以可以用来判断有向无环图,例如力扣207,思路和上面一致

    class Node {
        public Node[] son = new Node[26];
        boolean end; 
    }
    
    class Trie {
        privare Node = root;
    
        public Trie() {
            root = new Node();
        }
        
        public void insert(String word) {
            Mode cur = root;
            for (char c : word.toCharArray()) {
                c -= 'a';
                if (cur.son[c] == null) { // 插入值就是有子节点
                    cur.son[c] = new Node();
                }
                cur = cur.son[c];
            }
            cur.end = True;  // 防止遍历到最后一个空节点,来一个终止标记,也代表一共单词的截止
        }
        
        public boolean search(String word) {
            return find(word) == 2;  // 加入的单词末尾会有End=True
        }
        
        public boolean startsWith(String prefix) {
            return find(prefix) != 0;
        }
    
        private int find(String word) {
            Node cur = root;
            for (char c : word.toCharArray()) {
                c -= 'a';
                if (cur.son[c] == null) {
                    return 0;
                }
                cur = cur.son[c];
            }
            return cur.end ? 2 : 1
        }
    }
    
8.2.2多源bfs
  • 就是从不同点进行bfs,就像是一个区域,有几个污染的地方,那么肯定先污染附近的地方,多元bfs就这样

  • 例如力扣994:腐烂的橘子

    1. 先获得新鲜橘子数量和腐烂橘子的位置

    2. 去遍历腐烂橘子的位置,先污染周围的新鲜橘子,然后删除旧的污染橘子,因为周围的被污染过了,把新的污染橘子加进去,就是二次污染了。注意要区分一次污染和二次污染,这里隔离了存放位置的数组

      class Solution {
          private static int[][] DIRECTIONS = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
      
          // 多源BFS,由每个坏橘子只感染周围一圈的橘子,防止DFS那样多次判断修改同一个地方
          public int orangesRotting(int[][] grid) {
              int m = grid.length;
              int n = grid[0].length;
              List<int[]> bad = new ArrayList<>();
              int fresh = 0;
              // 先获取新鲜橘子数量,和坏橘子的位置
              for (int i = 0; i < m; i++) {
                  for (int j = 0; j < n; j++) {
                      if (grid[i][j] == 1) {
                          fresh++;
                      } else if (grid[i][j] == 2) {
                          bad.add(new int[]{i, j});
                      }
                  }
              }
      
              int ans = 0;
              while (!bad.isEmpty() && fresh > 0) {
                  ans++;
                  List<int[]> tep = bad;
                  bad = new ArrayList<>();
                  for (int[] a : tep) {
                      for (int[] d : DIRECTIONS) {
                          int i = a[0] + d[0];
                          int j = a[1] + d[1];
                          if (0 <= i && i < m && 0 <= j && j < n && grid[i][j] == 1) {
                              fresh--;
                              grid[i][j] = 2;
                              bad.add(new int[]{i, j});
                          }
                      }
                  }
              }
              return fresh > 0 ? -1 : ans;
          }
      }
      
  • Q&A

    1. 为什么不从新鲜橘子走,而是从腐烂橘子走

      如果从新鲜橘子走的话,肯定是遍历腐烂橘子的位置,这个时候如果很远的地方才有腐烂橘子,那么要隔很久才能污染,这里会有更加复杂的逻辑计算,所以不采用

    2. 为什么不用DFS?

      因为DFS是一条路走到死,因为此题有权重值,可能会导致一个地方被重复修改,需要加判断来确定留哪一次修改。

    3. 为什么用迭代不用递归

      和树的BFS同理,用递归首先更为方便,因为就是按照逻辑层序遍历,不是递归栈那样。用递归的BFS其实有点大材小用。

8.3Trim树
  1. 其实就是字典树,和正常的树不一样,节点其实存的是长度为26的数组,每一个值存的是下一个字母的数组的地址。还需要加一个遍历来表明是不是最后一个字母,比如apple是一个单词,在字典树,是一个数组,其中有一条这样的指向a->p->p->l->e是这样,我需要直到遍历到e这个数组直到是有一个单词的结尾,那么就加一个变量表明这里可以是一个结尾。

    逻辑如下

    class Node {
        public Node[] son = new Node[26];
        boolean end; 
    }
    
    class Trie {
        private Node root;
    
        public Trie() {
            root = new Node();
        }
        
        public void insert(String word) {
            Node cur = root;
            for (char c : word.toCharArray()) {
                c -= 'a';
                if (cur.son[c] == null) { // 插入值就是有子节点
                    cur.son[c] = new Node();
                }
                cur = cur.son[c];
            }
            cur.end = true;  // 防止遍历到最后一个空节点,来一个终止标记,也代表一共单词的截止
        }
        
        public boolean search(String word) {
            return find(word) == 2;  // 加入的单词末尾会有End=True
        }
        
        public boolean startsWith(String prefix) {
            return find(prefix) != 0;
        }
    
        private int find(String word) {
            Node cur = root;
            for (char c : word.toCharArray()) {
                c -= 'a';
                if (cur.son[c] == null) {
                    return 0;
                }
                cur = cur.son[c];
            }
            return cur.end ? 2 : 1;
        }
    }
    

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

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

相关文章

JVM性能优化一:初识内存泄露-内存溢出-垃圾回收

本文主要是让你充分的认识到什么叫做内存泄露&#xff0c;什么叫做内存溢出&#xff0c;别再傻傻分不清了&#xff0c;别再动不动的升级服务器的内存了。 文章目录 1.基本概念1.1.内存泄露1.2.内存溢出1.3.垃圾回收1.4.内存泄露-垃圾回收-内存溢出三者的关系关系 2.代码示例2.…

为什么使用环形队列

1.看以下两种情况。第一种不会出现问题&#xff0c;当主流程读取次数比较慢时&#xff0c;数据会被覆盖。 2.扩大空间。不可取。 3.什么是队列

【WRF教程第3.6期】预处理系统 WPS 详解:以4.5版本为例

预处理系统 WPS 详解&#xff1a;以4.5版本为例 Geogrid/Metgrid 插值选项详解1. 插值方法的工作机制2. 插值方法的详细说明2.1 四点双线性插值&#xff08;four_pt&#xff09;2.2 十六点重叠抛物线插值&#xff08;sixteen_pt&#xff09;2.3 简单四点平均插值&#xff08;av…

批量提取zotero的论文构建知识库做问答的大模型(可选)——含转存PDF-分割统计PDF等

文章目录 提取zotero的PDF上传到AI平台保留文件名代码分成20个PDF视频讲解 提取zotero的PDF 右键查看目录 发现目录为 C:\Users\89735\Zotero\storage 写代码: 扫描路径‘C:\Users\89735\Zotero\storage’下面的所有PDF文件,全部复制一份汇总到"C:\Users\89735\Downl…

Java模拟Mqtt客户端连接Mqtt Broker

Java模拟Mqtt客户端基本流程 引入Paho MQTT客户端库 <dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.mqttv5.client</artifactId><version>1.2.5</version> </dependency>设置mqtt配置数据 …

boost asio 异步服务器

boost网络框架使用方法 boost绑定 首先介绍io_context&#xff0c;可以理解为这是操作系统和应用层数据交互的桥梁。有了它不必关注内核态的缓冲区&#xff0c;只需要关注自己定义在用户态的缓冲区&#xff0c;因为它会通过桥梁运输到用户态的缓冲区。 boost::asio::io_contex…

图解HTTP-HTTP协议

HTTP HTTP是一种不保存状态&#xff0c;即无状态的协议。HTTP协议自身不对请求和响应之间的通信进行保存。为了保存状态因此后面也有一些技术产生比如Cookies技术。 HTTP是通过URI定位网上的资源&#xff0c;理论上将URI可以访问互联网上的任意资源。 如果不是访问特定的资源…

【Go】-限流器的四种实现方法

目录 关于限流和限流器 固定窗口限流器 滑动窗口限流器 漏桶限流器 令牌桶限流器 总结 关于限流和限流器 限流&#xff08;Rate Limiting&#xff09;是一种控制资源使用率的机制&#xff0c;通常用于防止系统过载和滥用。 限流器&#xff08;Rate Limiter&#xff09;是…

CTF_1

CTF_Show 萌新赛 1.签到题 <?php if(isset($_GET[url])){system("curl https://".$_GET[url].".ctf.show"); }else{show_source(__FILE__); }?> 和 AI 一起分析 1.if(isset($_GET[url]))检查GET请求中是否存在名为url的参数。 curl 2.curl…

[文献阅读] Unsupervised Deep Embedding for Clustering Analysis (无监督的深度嵌入式聚类)

文章目录 Abstract:摘要聚类深度聚类 KL散度深度嵌入式聚类(DEC)KL散度聚类软分配&#xff08;soft assignment&#xff09;KL散度损失训练编码器的初始化聚类中心的初始化 实验评估总结 Abstract: This week I read Unsupervised Deep Embedding for Clustering Analysis .It…

记录:virt-manager配置Ubuntu arm虚拟机

virt-manager&#xff08;Virtual Machine Manager&#xff09;是一个图形用户界面应用程序&#xff0c;通过libvirt管理虚拟机&#xff08;即作为libvirt的图形前端&#xff09; 因为要在Linux arm环境做测试&#xff0c;记录下virt-manager配置arm虚拟机的过程 先在VMWare中…

使用C语言编写UDP循环接收并打印消息的程序

使用C语言编写UDP循环接收并打印消息的程序 前提条件程序概述伪代码C语言实现编译和运行C改进之自由设定端口注意事项在本文中,我们将展示如何使用C语言编写一个简单的UDP服务器程序,该程序将循环接收来自指定端口的UDP消息,并将接收到的消息打印到控制台。我们将使用POSIX套…

Spring Boot 教程之三十六:实现身份验证

如何在 Spring Boot 中实现简单的身份验证&#xff1f; 在本文中&#xff0c;我们将学习如何使用 Spring设置和配置基本身份验证。身份验证是任何类型的安全性中的主要步骤之一。Spring 提供依赖项&#xff0c;即Spring Security&#xff0c;可帮助在 API 上建立身份验证。有很…

什么样的LabVIEW控制算自动控制?

自动控制是指系统通过预先设计的算法和逻辑&#xff0c;在无人工干预的情况下对被控对象的状态进行实时监测、决策和调整&#xff0c;达到预期目标的过程。LabVIEW作为一种图形化编程工具&#xff0c;非常适合开发自动控制系统。那么&#xff0c;什么样的LabVIEW控制算作“自动…

GFPS扩展技术原理(七)-音频切换消息流

音频切换消息流 Seeker和Provider通过消息流来同步音频切换能力&#xff0c;触发连接做切换&#xff0c;获取或设置音频切换偏好&#xff0c;通知连接状态等等。为此专门定义了音频切换消息流Message Group 为0x07&#xff0c;Message codes如下&#xff1a; MAC of Audio s…

视频直播点播平台EasyDSS与无人机技术的森林防火融合应用

随着科技的飞速发展&#xff0c;无人机技术以其独特的优势在各个领域得到了广泛应用&#xff0c;特别是在森林防火这一关键领域&#xff0c;EasyDSS视频平台与无人机技术的融合应用更是为传统森林防火手段带来很大的变化。 一、无人机技术在森林防火中的优势 ‌1、快速响应与高…

机器人路径规划和避障算法matlab仿真,分别对比贪婪搜索,最安全距离,RPM以及RRT四种算法

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1贪婪搜索算法原理 4.2最安全距离算法原理 4.3RPM 算法原理 4.4 RRT 算法原理 5.完整程序 1.程序功能描述 机器人路径规划和避障算法matlab仿真,分别对比贪婪搜索,最安全距离,RPM以及R…

【论文笔记】Visual Alignment Pre-training for Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Visual Alignment Pre-tra…

【附源码】Electron Windows桌面壁纸开发中的 CommonJS 和 ES Module 引入问题以及 Webpack 如何处理这种兼容

背景 在尝试让 ChatGPT 自动开发一个桌面壁纸更改的功能时&#xff0c;发现引入了一个 wallpaper 库&#xff0c;这个库的入口文件是 index.js&#xff0c;但是 package.json 文件下的 type:"module"&#xff0c;这样造成了无论你使用 import from 还是 require&…

Apache解析漏洞(apache_parsingCVE-2017-15715)

apache_parsing 到浏览器中访问网站 http://8.155.8.239:81/ 我们写一个木马 1.php.jpg 我们将写好的木马上传 会得到我们上传文件的路径 我们访问一下 发现上传成功 发现木马运行成功&#xff0c;接下来使用蚁剑连接我们的图片马 获取 shell 成功 CVE-2013-454 我们还是到…