算法-图BFS/DFS-单词接龙

算法-图BFS/DFS-单词接龙

1 题目概述

1.1 题目出处

https://leetcode-cn.com/problems/number-of-islands

1.2 题目描述

给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:

如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:

输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]

输出: 5

解释: 一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
返回它的长度 5。
示例 2:

输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]

输出: 0

解释: endWord “cog” 不在字典中,所以无法进行转换。

2 图-DFS

2.1 思路

将岛屿分布看做有向图,深度遍历该节点的上下左右四个方向。

遍历到一个为’1’的节点时,标记为’0’代表已经遍历过下次不再遍历。

2.2 代码

class Solution {
    public int numIslands(char[][] grid) {
        int result = 0;
        if(grid == null || grid.length == 0){
            return result;
        }
        
        for(int i = 0; i < grid.length; i++){
            char[] columns = grid[i];
            for(int j = 0; j < columns.length; j++){
                char c = columns[j];
                if(c == '1'){
                    dfs(grid, i, j);
                    result++;
                }
            }
        }
        return result;
    }
    private void dfs(char[][] grid, int row, int column){
        char[] columns = grid[row];
        char c = columns[column];
        if(c == '0'){
            return;
        }else{
            grid[row][column] = '0';
            if(column - 1 > -1){
                dfs(grid, row, column - 1);
            }
            if(column + 1 < columns.length){
                dfs(grid, row, column + 1);
            }
            if(row + 1 < grid.length){
                dfs(grid, row + 1, column);
            }
            if(row - 1 > -1){
                dfs(grid, row - 1, column);
            }
        }
    }
}

2.3 时间复杂度

在这里插入图片描述
O(N*M)

  • 其中 N 和 M 分别为行数和列数。

2.4 空间复杂度

O(N*M)

  • 因为需要递归

3 BFS

3.1 思路

将岛屿分布看做有向图,遍历开始后,从当前节点广度优先遍历。

3.2 代码

class Solution {
    private Set<String> recordSet = new HashSet<>();
    public int numIslands(char[][] grid) {
        int result = 0;
        if(grid == null || grid.length == 0){
            return result;
        }
        
        for(int i = 0; i < grid.length; i++){
            char[] columns = grid[i];
            for(int j = 0; j < columns.length; j++){
                char c = columns[j];
                if(c == '1'){
                    bfs(grid, i, j);
                    result++;
                }
            }
        }
        return result;
    }
    private void bfs(char[][] grid, int row, int column){
        char[] columns = grid[row];
        char c = columns[column];
        
        if(c == '0'){
            return;
        }
        LinkedList<int[]> coordinateQueue = new LinkedList<>();
        coordinateQueue.add(new int[]{row, column});
        // bfs
        while(!coordinateQueue.isEmpty()){
            int[] coordinate = coordinateQueue.poll();
            int i = coordinate[0];
            int j = coordinate[1];
            if(grid[i][j] == '0'){
                continue;
            }
            grid[i][j] = '0';
            if(j - 1 > -1){
                coordinateQueue.add(new int[]{i, j - 1});
            }
            if(j + 1 < columns.length){
                coordinateQueue.add(new int[]{i, j + 1});
            }
            if(i + 1 < grid.length){
                coordinateQueue.add(new int[]{i + 1, j});
            }
            if(i - 1 > -1){
                coordinateQueue.add(new int[]{ i - 1, j});
            }
        }
    }
}

3.3 时间复杂度

在这里插入图片描述
O(N*M)

  • 其中 N 和 M 分别为行数和列数。

3.4 空间复杂度

O(min(M,N))

  • 最坏情况全是岛屿

4 效率很低的第一版并查集

4.1 思路

做并查集,遇到相邻的’1’节点就合并成一个并查集。

最后返回不同的并查集数。

4.2 代码

class Solution {
    public int numIslands(char[][] grid) {
        int result = 0;
        if(grid == null || grid.length == 0){
            return result;
        }

        int[] unionFindSet = new int[grid.length * grid[0].length];
        
        for(int i = 0; i < grid.length; i++){
            char[] columns = grid[i];
            for(int j = 0; j < columns.length; j++){
                char c = columns[j];
                if(c == '1'){
                    // 初始化岛节点的并查集为index+1
                    find(unionFindSet, i * columns.length + j);
                    // 连接右侧节点
                    if(j + 1 < columns.length && grid[i][j + 1] == '1'){
                        // 这里需要将二维数组转为一位数组的下标
                        // 所以使用 当前行*列总数得到该行在一位数组中的首个下标,
                        // 再加上当前列作为偏移数得到在一维数组的下标
                        union(unionFindSet, i * columns.length + j, i * columns.length + j + 1);
                    }
                    // 连接下侧节点
                    if(i + 1 < grid.length && grid[i+1][j] == '1'){
                        union(unionFindSet, i * columns.length + j, (i + 1) * columns.length + j);
                    }
                }
            }
        }
        Set<Integer> filter = new HashSet<>();
        for(int i : unionFindSet){
            if(i != 0){
                filter.add(i);
            }
        }
        return filter.size();
    }

    private void union(int[] unionFindSet, int p, int q){
        int left = find(unionFindSet, p);
        int right = find(unionFindSet, q);
        if(left == right){
            return;
        }
        // 查找出所有和右边元素同一个并查集元素,和左边合并
        for(int i = 0; i < unionFindSet.length; i++){
            if(unionFindSet[i] == right){
                unionFindSet[i] = left;
            }
        }
    }

    private int find(int[] unionFindSet, int p){
        if(unionFindSet[p] == 0){
            unionFindSet[p] = p + 1;
        }
        return unionFindSet[p];
    }
}

4.3 时间复杂度

在这里插入图片描述

5 并查集-优化

5.1 思路

合并两个不同祖先的节点时,将他们的祖先合并为一个即可。

最后遍历计算出不同的祖先数作为结果返回。

在union的时候还采用了压缩路径优化方法,提升查找效率。

5.2 代码

class Solution {
    public int numIslands(char[][] grid) {
        int result = 0;
        if(grid == null || grid.length == 0){
            return result;
        }

        int[] unionFindSet = new int[grid.length * grid[0].length];

        // 初始化所有节点的并查集,父节点设为自己
        for(int i = 0; i < grid.length; i++){
            char[] columns = grid[i];
            for(int j = 0; j < columns.length; j++){
                unionFindSet[i * columns.length + j] = i * columns.length + j;
            }
        }
        // 下面开始合并岛节点
        for(int i = 0; i < grid.length; i++){
            char[] columns = grid[i];
            for(int j = 0; j < columns.length; j++){
                char c = columns[j];
                if(c == '1'){
                    // 初始化岛节点的并查集为index+1
                    // find(unionFindSet, i * columns.length + j);
                    // 连接右侧节点
                    if(j + 1 < columns.length && grid[i][j + 1] == '1'){
                        // 这里需要将二维数组转为一位数组的下标
                        // 所以使用 当前行*列总数得到该行在一位数组中的首个下标,
                        // 再加上当前列作为偏移数得到在一维数组的下标
                        union(unionFindSet, i * columns.length + j, i * columns.length + j + 1);
                    }
                    // 连接下侧节点
                    if(i + 1 < grid.length && grid[i+1][j] == '1'){
                        union(unionFindSet, i * columns.length + j, (i + 1) * columns.length + j);
                    }
                }else{
                    // 海洋节点,将他们的父节点设为-1,不参与累计
                    unionFindSet[i * columns.length + j] = -1;
                }
            }
        }
        // 去重根节点
        Set<Integer> filter = new HashSet<>();
        // 将所有父节点不为-1的节点全部取出,并寻找他们的父节点
        // 只要父节点不为-1就放入过滤器统计
        for(int i = 0; i < unionFindSet.length; i++){
            if(unionFindSet[i] == -1){
                continue;
            }
            int root = find(unionFindSet, i);
            if(root > -1){
                filter.add(root);
            }
        }
        // 最终返回不重复的根节点数
        return filter.size();
    }

    private void union(int[] unionFindSet, int p, int q){
        int left = find(unionFindSet, p);
        int right = find(unionFindSet, q);
        // 说明本来就在一个并查集内,不用处理
        if(left == right){
            return;
        }
        // 将右边元素的老祖先作为左边元素老祖先的父节点,实现联通
        unionFindSet[left] = right;
    }

    private int find(int[] unionFindSet, int p){
        int son = p;
        // 寻找祖先根节点
        while(p != unionFindSet[p]){
            p = unionFindSet[p];
        }
        // 路径压缩优化,将当前节点及祖先节点的父节点都设为祖先根节点
        // 即将高度压缩为2,方便查找
        while(son != p){
            int tmp = unionFindSet[son];
            unionFindSet[son] = p;
            son = tmp;
        }
        return p;
    }    
}

5.3 时间复杂度

在这里插入图片描述
参考岛屿数量

5.4 空间复杂度

O(M*N)

参考文档

  • 算法-并查集

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

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

相关文章

C++八股记录

C内存管理 C中&#xff0c;内存分成5个区。 栈&#xff1a;函数内局部变量&#xff1b;自动管理&#xff0c;效率高&#xff0c;但空间较小&#xff1b; 堆&#xff1a;new分配的内存块&#xff1b;手动管理&#xff0c;效率低&#xff0c;但空间大&#xff1b; 自由存储区&…

代码复现,我能行之DMP-MATLAB

代码复现&#xff0c;我能行——系列一 一、基础概念 Dynamic Movement Primitives &#xff08;DMP&#xff09;&#xff0c;中文为动态运动基元或动态运动原语&#xff0c;由美国University of Southern California的Stefan Schaal教授团队于2002年提出&#xff0c;是一种用…

2023年智慧政务一网通办云平台顶层设计与建设方案PPT

导读:原文《2023年智慧政务一网通办云平台顶层设计与建设方案PPT》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 部分内容:

计算机竞赛 基于Django与深度学习的股票预测系统

文章目录 0 前言1 课题背景2 实现效果3 Django框架4 数据整理5 模型准备和训练6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于Django与深度学习的股票预测系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff…

GIT 常用指令

基础指令 $ git init #初始化仓库&#xff0c;在该文件夹创建的为workspace$ git add . #已暂存 [.通配符&#xff0c;全部添加]$ git commit -m "log add file" #提交到仓库,并写了日志 ”log add file“$ git status #查看状态&#xff0c;可查看被修改的文件…

win11出现安全中心空白和IT管理员已限制对此应用的某些区域的访问

问题 windows安全中心服务被禁用 winr 输入services.msc 找到windows安全中心服务查看是否被禁用&#xff0c;改为启动&#xff0c;不可以改动看第三条 打开设置&#xff0c;找到应用—windows安全中心–终止–修复–重置 重启如果还是不行看第四条 家庭版系统需要打开gped…

新手指南:7个步骤制定成功的项目预算

每个项目都涉及成本。项目越大、越复杂&#xff0c;执行的时间和金钱成本就越高。企业不会拥有无限的资源&#xff0c;所以每个项目都需要项目预算。 但挑战在于&#xff1a;确定项目需要多少预算并不总是那么容易。低估需求&#xff0c;最终会导致人手短缺&#xff0c;无法按…

数组中出现次数超过一半的数字

⭐️ 题目描述 &#x1f31f; OJ链接&#xff1a;数组中出现次数超过一半的数字 思路&#xff1a; 采用投票计数的方式&#xff0c;我们可以把每个数字都看成一次投票并且计数&#xff0c;那么最后剩下来的就是数组中数字出现次数最多的那一个。比如 { 1,2,3,2,2,2,5,4,2 } &a…

《动手学深度学习》-57长短期记忆网络LSTM

沐神版《动手学深度学习》学习笔记&#xff0c;记录学习过程&#xff0c;详细的内容请大家购买书籍查阅。 b站视频链接 开源教程链接 长短期记忆网络&#xff08;LSTM&#xff09; 长期以来&#xff0c;隐变量模型存在长期信息保存和短期输入缺失的问题。解决这一问题的最早…

【C# Programming】编程入门:数组、操作符、控制流

目录 一、数组 1、数组的声明 1.1 一维数组声明&#xff1a; 1.2 多维数组声明&#xff1a; 2、数组的实例化和赋值 2.1 数组在声明时通过在花括号中使用以逗号分隔的数据项对数组赋值&#xff0c; 例如&#xff1a; 2.2 如果在声明后赋值&#xff0c;则需…

算法通过村第四关-栈青铜笔记|手写栈操作

文章目录 前言1. 栈的基础概要1.1 栈的特征1.2 栈的操作1.3 Java中的栈 2. 栈的实现&#xff08;手写栈&#xff09;2.1 基于数组实现2.2 基于链表实现2.3 基于LinkedList实现 总结 前言 提示&#xff1a;我自己一个人的感觉很好 我并不想要拥有你 除非你比我的独处更加宜人 --…

探索生成式人工智能的前景

一、什么是生成式人工智能&#xff1f; 生成式人工智能&#xff08;Generative AI&#xff09;是一类人工智能&#xff08;AI&#xff09;技术和模型&#xff0c;旨在创建新颖的内容。与简单的复制不同&#xff0c;这些模型通过利用从训练数据集中收集到的模式和见解&#xff…

nginx-concat

为了减少tcp请求数量&#xff0c;nginx从上有服务器获取多个静态资源&#xff08;css&#xff0c;js&#xff09;的时候&#xff0c;将多个静态资源合并成一个返回给客户端。 这种前面有两个问号的请求都是用了cancat合并功能。 先到官网下载安装包&#xff0c;拷贝到服务器编译…

弯道超车必做好题集锦三(C语言选择题)

前言&#xff1a; 编程想要学的好&#xff0c;刷题少不了&#xff0c;我们不仅要多刷题&#xff0c;还要刷好题&#xff01;为此我开启了一个弯道超车必做好题锦集的系列&#xff0c;每篇大约10题左右。此为第三篇选择题篇&#xff0c;该系列会不定期更新&#xff0c;后续还会…

C#_特性反射详解

特性是什么&#xff1f; 为程序元素额外添加声明信息的一种方式。 字面理解&#xff1a;相当于把额外信息写在干胶标签上&#xff0c;然后将其贴在程序集上。 反射是什么&#xff1f; 反射是一种能力&#xff0c;运行时获取程序集中的元数据。 字面理解&#xff1a;程序运行…

防溺水智能预警系统解决方案 yolov7

防溺水智能预警系统解决方案采用yolov7先进的AI视觉识别算法模型框架&#xff0c;防溺水智能预警系统解决方案算法实现对危险水域人员活动、水面情况等各项指标的监测和分析。当发现有人进入危险水域或出现紧急情况时&#xff0c;算法会立即发出预警信号。Yolo算法采用一个单独…

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片,Kotlin

Android Glide preload RecyclerView切入后台不可见再切换可见只加载当前视野可见区域item图片&#xff0c;Kotlin <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name"android.permission.RE…

使用Nacos与Spring Boot实现配置管理

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Qt6和Rust结合构建桌面应用

桌面应用程序是原生的、快速的、安全的&#xff0c;并提供Web应用程序无法比拟的体验。 Rust 是一种低级静态类型多范式编程语言&#xff0c;专注于安全性和性能&#xff0c;解决了 C/C 长期以来一直在努力解决的问题&#xff0c;例如内存错误和构建并发程序。 在桌面应用程序开…

单片机电子元器件-数码管

数码管分类 共阳 把所有数码管的阳极接到一起形成公共阳极COM 数码管 共阳极COM 接到 5V 电源 共阴 把所有数码管的阴极接到一起形成公共阴极COM 数码管 共阴极COM 接到 地 GND 上 八段 数码管 和 七段数码管&#xff0c; 多了一个 小数点 DP 数码管显示原理 一个数码管如…