leetcode 图论专题——(dfs+bfs+并查集 回顾)

news2024/12/29 11:39:11

DFS、BFS

回顾(C语言代码)
map[i][j]里记录的是i点和j点的连接关系

基本DFS:

int vis[101],n,map[101][101];
void dfs(int t)
{
    int i;
    vis[t]=1;
    for(i=0;i<n;i++)//找对t点所有有关联的点——“找路”
    {
        if(vis[i]!=0&&map[t][i]==1)//有连接边的点且没访问过
        {
            printf(" %d",i);
            dfs(i);
        }
    }
}
dfs(0);

通过BFS找从起点到终点的最短步数

int n;
int map[1001][1001],vis[1001];
int quee[1001];//用个队列存着与当前点有连接边的点
int num[1001];//bfs下起点到各个点的步数
void bfs(int t)
{
    memset(vis,0,sizeof(vis));
    memset(num,1061109567,sizeof(num));
    memset(quee,0,sizeof(quee));
    int k,kk,i;
    k=0;
    kk=0;
    num[t]=0;//n到n 为0步
    quee[k++]=t;//在队列中放入起点
    vis[t]=1;
    while(kk<k)//队列不为空
    {
        int now=quee[kk++];//依次拿出队列中的节点
        for(i=1; i<=n; i++)//找路
        {
            if(vis[i]==0&&map[now][i]==1)//当前结点与i结点连通 && 没有遍历过
            {
                quee[k++]=i;
                vis[i]=1;		
                if(num[now]<num[i])//当前now点到i点距离更短,那就在num[now]的基础上+1
                    num[i]=num[now]+1;
            }
        }
    }
    
    if(num[n]==1061109567)//起点到终点距离是inf,说明到不了
        printf("NO\n");
    else printf("%d\n",num[n]);
}

在二维图迷宫里从起点到终点的路径数(dfs)

(这题需要注意的是,每次移动并不总是向着接近终点的放心走,可以在不重复的前提下乱窜,所以导致有很多条路)

int n,m,num;
int map[11][11],vis[11][11];
void dfs(int x,int y)
{
    int i,tx,ty;
    int next[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//下上右左 4种移动方式
   	vis[x][y]=1;
    if(x==n&&y==m)
    {
        num++;//每次到终点计数
        return ;
    }
    for(i=0;i<4;i++)//与for(0,n)一样都是去判断相连的点即“找路”
    {
        tx=x+next[i][0];//每次移动
        ty=y+next[i][1];
        if(tx<1||tx>n||ty<1||ty>m)//是否越界
        {
            continue;
        }
        if(vis[tx][ty]==0&&map[tx][ty]==0)//当前点可以走且没走过
        {
            vis[tx][ty]=1;
            dfs(tx,ty);
            vis[tx][ty]=0;//释放
        }
    }
}

dfs(1,1);//起点(1,1) 终点(n,m)

在二维图里从起点到终点的最短步数(bfs)

struct node
{
    int x,y,time;
} quee[101],now,t;//队列要记录xy坐标和到这点的步数
char map[16][16];
int n,m,vis[16][16];
void bfs(int x0,int y0)
{
    int i,k,kk;
    int next[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    memset(quee,0,sizeof(quee));
    vis[x0][y0]=1;
    t.x=x0;t.y=y0;t.time=0;
    quee[0]=t;//起点信息放队列
    
    k=1;kk=0;
    while(kk<k)
    {
        now=quee[kk++];
        if(map[now.x][now.y]=='Y')//到终点
        {
            printf("%d\n",now.time);
            return ;
        }
        for(i=0; i<4; i++)//二维找路
        {
            t.x=now.x+next[i][0];
            t.y=now.y+next[i][1];
            if(t.x<0||t.x>=n||t.y<0||t.y>=m)
            {
                continue;
            }
            if(vis[t.x][t.y]==0&&map[t.x][t.y]!='#')//可以通行
            {
                t.time=now.time+1;
                quee[k++]=t;
                vis[t.x][t.y]=1;
            }
        }
    }
    printf("-1\n");
}

bfs(i1,j1);//起点传进去

java-简单并查集类

单维点

class UnionFind {
    private int[] parent;//记录祖先节点是谁
    private int[] rank;//统计此节点做了几次祖先了

    public UnionFind(int n) {//初始化
        parent = new int[n];//new空间
        for (int i = 0; i < n; i++) {
            parent[i] = i;//先让所有点的祖先是自己
        }
        rank = new int[n];
    }

    public void union(int x, int y) {//合并
        int rootx = find(x);
        int rooty = find(y);
        if (rootx != rooty) {//谁rank大谁做祖先
            if (rank[rootx] > rank[rooty]) {
                parent[rooty] = rootx;
            } else if (rank[rootx] < rank[rooty]) {
                parent[rootx] = rooty;
            } else {
                parent[rooty] = rootx;
                rank[rootx]++;
            }
        }
    }

    public int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);//找到并和祖先直接相连
        }
        return parent[x];//返回祖先
    }
}

二维图,点由(x,y)坐标组成

class UnionFind {
        int[] parent;
        int[] rank;

        public UnionFind(char[][] grid) {//初始化
            count = 0;
            int m = grid.length;
            int n = grid[0].length;
            parent = new int[m * n];
            rank = new int[m * n];
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (grid[i][j] == '1') {
                        parent[i * n + j] = i * n + j;//将坐标(i,j)以数组下标的形式
                    }
                    rank[i * n + j] = 0;
                }
            }
        }

        public int find(int i) {
            if (parent[i] != i)
            	parent[i] = find(parent[i]);
            return parent[i];
        }

        public void union(int x, int y) {
            int rootx = find(x);
            int rooty = find(y);
            if (rootx != rooty) {
                if (rank[rootx] > rank[rooty]) {
                    parent[rooty] = rootx;
                } else if (rank[rootx] < rank[rooty]) {
                    parent[rootx] = rooty;
                } else {
                    parent[rooty] = rootx;
                    rank[rootx]++;
                }
            }
        }
    }

leetcode

200. 岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

示例 :
输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3

关键:通过基础二维图dfs遍历图

class Solution {
    int[][] vis=new int[303][303];
    int n,m;
    void dfs(char[][] map,int x,int y){
        int i,tx,ty;
        int[][] next={{1,0},{-1,0},{0,1},{0,-1}};//下上右左 4种移动方式
        vis[x][y]=1;

        for(i=0;i<4;i++){
            tx=x+next[i][0];
            ty=y+next[i][1];
            if(tx<0||tx>=n||ty<0||ty>=m){
                continue;
            }
            if(vis[tx][ty]==0&&map[tx][ty]=='1'){
                vis[tx][ty]=1;
                dfs(map,tx,ty);
            }
        }
    }
    public int numIslands(char[][] grid) {
        n=grid.length;
        m=grid[0].length;
        int cnt=0;
        //对图中所有没访问过的点做dfs
       for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(vis[i][j]==0&&grid[i][j]=='1'){
                dfs(grid,i,j);
                cnt++;//每次从新起点开始dfs就是一个独立的岛屿
            }
        }
       }
       return cnt;
        
    }
}

还可以并查集,将相邻且为1的在并查集里合并,最后统计由几个祖先节点。

1559. 二维网格图中探测环

给你一个二维字符网格数组 grid ,大小为 m x n ,你需要检查 grid 中是否存在 相同值 形成的环。
一个环是一条开始和结束于同一个格子的长度 大于等于 4 的路径。对于一个给定的格子,你可以移动到它上、下、左、右四个方向相邻的格子之一,可以移动的前提是这两个格子有 相同的值 。
同时,你也不能回到上一次移动时所在的格子。比方说,环 (1, 1) -> (1, 2) -> (1, 1) 是不合法的,因为从 (1, 2) 移动到 (1, 1) 回到了上一次移动时的格子。
如果 grid 中有相同值形成的环,请你返回 true ,否则返回 false 。
示例 :
在这里插入图片描述
输入:grid = [[“c”,“c”,“c”,“a”],[“c”,“d”,“c”,“c”],[“c”,“c”,“e”,“c”],[“f”,“c”,“c”,“c”]]
输出:true

class Solution {
    int[][] vis = new int[505][505];
    int flag;
    int n,m;
    
    void dfs(char[][] map,int x,int y,int xx,int yy)//x,y是当前点坐标
{                                 //xx,yy是x,y,前一步点的坐标
    vis[x][y]=1;
    if(flag==1) return ;
    /* (x,y)向上下左右移动 */
    if(x-1>=0&&map[x-1][y]==map[x][y]) //向上存在且同色
    {
        if(vis[x-1][y]==1&&(x-1!=xx||y!=yy)) 通过下一步(x-1,y)不是上一步(xx,yy),但这个下一步曾经走过,就说明成环了
        {                                  
            flag=1;
        }
        else if(vis[x-1][y]==0)  //没形成环就继续遍历
            dfs(map,x-1,y,x,y);
    }
    if(y+1<m&&map[x][y+1]==map[x][y])//向右存在且同色
    {
        if(vis[x][y+1]==1&&(x!=xx||y+1!=yy))
        {
            flag=1;
        }
        else if(vis[x][y+1]==0)
            dfs(map,x,y+1,x,y);
    }
    if(x+1<n&&map[x+1][y]==map[x][y])//向下存在且同色
    {
        if(vis[x+1][y]==1&&(x+1!=xx||y!=yy))
        {
            flag=1;
        }
        else if(vis[x+1][y]==0)
            dfs(map,x+1,y,x,y);
    }
    if(y-1>=0&&map[x][y-1]==map[x][y])//向左存在且同色
    {
        if(vis[x][y-1]==1&&(x!=xx||y-1!=yy))
        {
            flag=1;
        }
        else if(vis[x][y-1]==0)
            dfs(map,x,y-1,x,y);
    }
}

    public boolean containsCycle(char[][] grid) {
        flag=0;
        n=grid.length;
        m=grid[0].length;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                if(vis[i][j]==0)//对每个没访问过的点都进行成环dfs测试
                {
                    dfs(grid,i,j,i,j);
                }
                if(flag==1)
                    break;
            }
            if(flag==1) break;
        }
        if(flag==1)return true;
        else return false;

    }
}

官方解,时间复杂度更低的使用并查集,通过连通性判断网格中是否有相同值形成的环,连通性问题可以使用并查集解决
(没看明白)

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

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

相关文章

怎么将jar注册为windows系统服务详细操作

将spring boot项目编译成jar,注册为windows系统服务 在网上了解到,winsw这个开源项目,去github看了下,作者常年维护更新,文档齐全,拥有不少,自己写了个小demo体验了下还不错,然后又运行了一个晚上,没啥问题,遂决定采用它 开源地址 源库地址 https://github.com/winsw/winsw R…

string类简单的底层实现,了解string底层以及string的补充知识

string类的简单实现 头文件 #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> #include<assert.h> using namespace std; namespace exprience {class string {public:typedef char* iterator;iterator begin(){return _str;}iterator end()…

IPython使用技巧详解:提高Python编程效率的利器

目录 一、IPython基础设置与启动 1.1 安装IPython 1.2 IPython的配置 二、IPython交互式编程体验 2.1 魔术命令(Magic Commands) 2.2 变量自动补全与文档查看 2.3 历史命令与快速访问 三、IPython高级功能 3.1 列表推导式与生成器表达式 3.2 枚举与压缩函数 3.3 L…

Java NIO(Non-blocking I/O)简单理解

Java NIO是Java平台中用于高效输入/输出&#xff08;I/O&#xff09;操作的一套新的API&#xff0c;与标准的Java I/O&#xff08;基于流的阻塞I/O&#xff09;不同&#xff0c;Java NIO提供了非阻塞式的I/O操作。 Java NIO 的核心组件 Java NIO主要由以下几个核心部分组成&a…

服务器网络不通排查方案

服务器网络不通排查方案 最近遇到了服务器上服务已经启动&#xff0c;但是在浏览器上无法访问的问题&#xff0c;记录一下排查流程 文章目录 服务器网络不通排查方案netstart排查网络连接信息netstat 命令netstat -aptn 命令 iptables总结 netstart排查网络连接信息 netstat …

【Linux进程篇】进程终章:POSIX信号量线程池线程安全的单例模式自旋锁读者写者问题

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 前言&#xff1a;在之前的进程间通信时我们就讲到过信号量&#xff0c;他的本质就是一个计数器&#xff0c;用来描述临界资源的一个计数器。我们当时使用电影院的例子来说明信号量。电影院的座位被我们称为临界资源&a…

LVS集群实现四层负载均衡详解(以nat,dr模式为例)

目录 一、LVS集群的介绍 1、LVS 相关术语&#xff1a; 2、lvs工作原理 3、相关名词概念 4、lvs集群的类型 二、lvs的nat模式 1、介绍&#xff1a; 2、数据逻辑&#xff1a; 3、nat实验部署 环境搭建&#xff1a; 1、lvs中要去打开内核路由功能&#xff0c;实现网络互联…

关于区块链的公共医疗应用开发

区块链的养老保险平台应用开发 任务一:环境准备 1.编译区块链网络 目录:/root/xuperchain/ 在区块链网络目录下执行make命令,编译网络,编译成功后输出compile done! 启动区块链网络 2.创建钱包账户 创建普通钱包账户userTest,命令如下 bin/xchain-cli account newke…

6.2 Python 标准库简介:编程世界的百宝箱

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…

QT界面设计开发(Visual Studio 2019)—学习记录一

一、控件升级 简要介绍&#xff1a; 简单来说&#xff0c;控件提升就是将一个基础控件&#xff08;Base Widget&#xff09;转换为一个更特定、更复杂的自定义控件&#xff08;Custom Widget&#xff09;。这样做的目的是为了在设计界面时能够使用更多高级功能&#xff0c;而不…

QT下载与安装

我们要下载开源的QT&#xff0c;方式下载方式&#xff1a; 官网 登录地址&#xff1a;http://www.qt.io.com 点击右上角的Download. Try.按钮&#xff1b;进入一下画面&#xff1a; 如果进入的是以下画面&#xff1a; 直接修改网址&#xff1a;www.qt.io/download-dev; 改为w…

pytorch的gpu环境安装

windows系统下pytorch的gpu环境安装 安装前置说明&#xff1a; 要成功安装pytorch的gpu环境&#xff0c;需要cuda版本&#xff0c;python版本和pytorch版本都要相匹配才能顺利使用&#xff0c;cuda版本建议不要安装最新的版本&#xff0c;以免找不到相匹配的pytorch版本pytho…

八问八答,深入浅出搞懂Transformer内部运作原理

导读 同学们在学习Transformer时是否觉得难以理解或者很难理清其内部运作原理呢。本文将通过八个关键问题帮助大家搞懂Transformer内部工作原理&#xff0c;希望对大家有所帮助。 七年前&#xff0c;论文《Attention is all you need》提出了 transformer 架构&#xff0c;颠…

KVM——虚拟机的复制与克隆

目录 一. 复制虚拟机 二. 虚拟机克隆 1. 使用 virt-clone 2. 使用 virt-manager&#xff08;图形界面&#xff09; 3. 使用 qemu-img &#xff08;磁盘镜像克隆&#xff09; 一. 复制虚拟机 配置文件路径&#xff1a;/etc/libvirt/qemu/*.xml 磁盘镜像文件路径&#…

【扒代码】regression_head.py

import torch from torch import nnclass UpsamplingLayer(nn.Module):# 初始化 UpsamplingLayer 类def __init__(self, in_channels, out_channels, leakyTrue):super(UpsamplingLayer, self).__init__() # 调用基类的初始化方法# 初始化一个序列模型&#xff0c;包含卷积层、…

LeetCode 7, 703, 287

文章目录 7. 整数反转题目链接标签思路反转操作反转的数的范围 代码 703. 数据流中的第 K 大元素题目链接标签思路代码 287. 寻找重复数题目链接标签思路代码 7. 整数反转 题目链接 7. 整数反转 标签 数学 思路 反转操作 反转实际上很简单&#xff0c;假设要反转数字 n…

数据结构之Map与Set(上)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 目录 二叉搜索树 Map和Set的介绍与使用 Map的常用方法及其示例 Set的常用方法及其示例 哈希表…

客户管理系统平台(CRM系统)是什么?它的核心主要解决哪些问题?

客户管理系统平台CRM是什么&#xff1f;客户关系管理系统CRM的核心主要解决哪些问题&#xff1f; CRM系统不仅仅是一套软件&#xff0c;更是一种策略&#xff0c;一种管理理念和一种企业发展方向。它通过整合客户数据、优化业务流程、提升客户体验&#xff0c;帮助企业在激烈的…

K8s第三节:k8s1.23.1升级为k8s1.30.0

上回书说到我们使用了kubeadm安装了k8s1.23.1,但是在k8s1.24之前还是使用docker作为容器运行时&#xff0c;所以这一节我打算将我安装的k8s集群升级为1.30.0版本&#xff1b; 1、修改containerd 配置 因为我们安装的docker自带containerd&#xff0c;所以我们不需要重新安装con…

蓝凌EKP二次开发资料大全 完整蓝凌二次开发资料 蓝凌 EKP开发实战教程 蓝凌OA二次开发资料大全 蓝凌OA java开发快速入门

蓝凌EKP二次开发资料大全 完整蓝凌二次开发资料 蓝凌 EKP开发实战教程 蓝凌OA二次开发资料大全 记得两年前花了非常贵的费用去现场学习的资料&#xff0c;把这些开发技术文档分享出来&#xff0c;希望通过这个资料&#xff0c; 为大家学习开发大大减少时间。期待大家能快速上…