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

这篇具有很好参考价值的文章主要介绍了算法-图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 时间复杂度

算法-图BFS/DFS-单词接龙,算法,宽度优先,深度优先
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 时间复杂度

算法-图BFS/DFS-单词接龙,算法,宽度优先,深度优先
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 时间复杂度

算法-图BFS/DFS-单词接龙,算法,宽度优先,深度优先

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 时间复杂度

算法-图BFS/DFS-单词接龙,算法,宽度优先,深度优先
参考岛屿数量

5.4 空间复杂度

O(M*N)文章来源地址https://www.toymoban.com/news/detail-685761.html

参考文档

  • 算法-并查集

到了这里,关于算法-图BFS/DFS-单词接龙的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深度优先搜索(DFS)和广度优先搜索(BFS)两种算法c++

    深度优先搜索(DFS)和广度优先搜索(BFS)是一种用于遍历或搜索树图的一种算法,在这个过程中保证图或数的每个结点被访问且仅被访问一次,再按照每个结点访问的顺序不同分为深搜和广搜。 本文只讨论这两种算法在搜索方面的应用! 深度优先搜索 ( Depth-First-Search,DFS )它 沿

    2024年02月13日
    浏览(33)
  • 【数据结构与算法】搜索算法(深度优先搜索 DFS和广度优先搜索 BFS)以及典型算法例题

    【数据结构与算法】系列文章链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题) 【数据结构与算法】系列文章链接: 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题 【数据结构与算法】系列文章链

    2024年04月13日
    浏览(36)
  • 基于邻接矩阵的有向图的广度优先遍历(BFS)和深度优先遍历(DFS)算法

    概念: 广度优先遍历算法是图的另一种基本遍历算法,其基本思想是尽最大程度辐射能够覆盖的节点,并对其进行访问。 以迷宫为例,广度优先搜索则可以想象成一组人一起朝不同的方向走迷宫,当出现新的未走过的路的时候,可以理解成一个人有分身术,继续从不同的方

    2024年02月06日
    浏览(49)
  • 数据结构与算法基础-学习-24-图的遍历之DFS(深度优先搜索)和BFS(广度优先搜索)

    目录 一、遍历定义 二、遍历实质 三、DFS 四、BFS 五、宏定义 六、自定义类型 七、函数实现 1、DFS(邻接矩阵实现) 2、DFS(邻接表实现) 3、BFS(邻接矩阵实现) 4、BFS(邻接表实现) 5、打印邻接矩阵遍历顺序  6、打印邻接表遍历顺序 八、遍历算法效率分析 1、DFS 2、BFS 九

    2024年02月03日
    浏览(59)
  • 【算法导论】图论(图的基本概念,图上的深度优先搜索(DFS),广度优先搜索(BFS),最小生成树(MST)及Prim,Kruskal算法)

    图(Graph)是一种包含节点与节点的边的集合,记作G=(V,E),V是节点的集合,E是边的集合。 有向图 一个有向图G=(V,E),E中每个元素是V上的一个二值关系:一条从a出发的连向b的边e可以记作一个 有序 对e = (a,b) 。 无向图 一个无向图G=(V,E),E的每个元素e可以表示V上的一个 无序 对,记

    2024年02月03日
    浏览(33)
  • 深度优先搜索(DFS)和广度优先搜索(BFS)

    代码随想录 深度优先搜索和广度优先搜索,都是图形搜索算法,它两相似,又却不同,在应用上也被用到不同的地方。这里拿一起讨论,方便比较。 先给大家说一下两者大概的区别: 如果搜索是以接近起始状态的程序依次扩展状态的,叫广度优先搜索。 如果扩展是首先扩展

    2024年02月02日
    浏览(40)
  • 深度优先搜索(DFS)和广度优先搜索(BFS)

    深度优先搜索(DFS)和广度优先搜索(BFS)是图论中两个非常重要的算法,主要用于拓扑排序,寻路(走迷宫)和搜索引擎等。在我们写算法时经常会遇到需要使用DFS和BFS的题目,例如leetcode中的岛屿相关的问题以及有关树的题目大多都会使用DFS或者BFS。 深度优先搜索 深度优

    2024年02月10日
    浏览(33)
  • 对无向图进行邻接矩阵的转化,并且利用DFS(深度优先)和BFS(广度优先)算法进行遍历输出, 在邻接矩阵存储结构上,完成最小生成树的操作。

    目录 一 实验目的 二 实验内容及要求 实验内容: 实验要求: 三 实验过程及运行结果 一 算法设计思路 二 源程序代码 三、截图 四 调试情况、设计技巧及体会 1.掌握图的相关概念。 2.掌握用邻接矩阵和邻接表的方法描述图的存储结构。 3.掌握图的深度优先搜索和广度优

    2024年02月04日
    浏览(43)
  • 算法:BFS宽度优先遍历

    本篇总结的是BFS算法,BFS算法相比起DFS算法来说还是比较简单的 这里提供一种双端队列的做法,也可以在合适的层数逆序

    2024年02月21日
    浏览(38)
  • 宽度优先搜索算法(BFS)

    宽度优先搜索算法(BFS) (也称为 广度优先搜索 )主要运用于树、图和矩阵(这三种可以都归类在图中),用于在图中从起始顶点开始 逐层 地向外探索,直到找到目标顶点为止。 在本篇文章中,我们主要讨论其在 树 中的运用 树的宽度优先搜索 即 树的层序遍历 :逐层访

    2024年03月12日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包