Leetcode热题100:图论

news2025/1/11 0:54:26

Leetcode 200. 岛屿数量

深度优先搜索法:

对于这道题来说,是一个非常经典的图的问题,我们可以先从宏观上面来看问题,也就是说在不想具体算法的前提下,简单的说出如何找到所有的岛屿呢?

如图中所示,首先非常显而易见的要素就是我们一定要遍历图中的每一个坐标,这是肯定的,然后呢对于岛屿的数量,一开始想的肯定就是每当我们访问了一个1的坐标时,我们就找到了一个岛屿,可是因为我们要遍历整个图,所以肯定不能每次遇到一个1就对岛屿的数量进行增加,因为题目说了,横纵连接着的坐标都是1的话都属于同一个岛屿,就像上图一样证明我们只有三个岛屿

那么我们是不是可以像一个办法,当我们找到了一个岛屿的坐标后,把属于这个坐标的岛屿的其他所有值为1的坐标都记录下来,这样以来,意思就是说在我们继续遍历的时候,我们检查每一个坐标时,如果发现这个坐标已经被标记过了,证明他并不是一个新的岛屿而是一个之前就发现过的岛屿的一部分那么就可以了

如何去实现这个标记的方法呢,就可以用到我们的深度优先搜索,从新发现的坐标开始一直找,直到找到了岛屿的边缘或者整个图的边缘之后返回,这样就能找到所有属于相同岛屿的坐标,那么我们可以把主代码写出来了已经

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        res = 0

        # iterate to check every box in the grid to see
        # if it is a start for a new lsland
        for r in range(len(grid)):
            for c in range(len(grid[0])):
                
                # if so, run a dfs to mark all its fellow
                # box and add the 1 to the result
                if grid[r][c] == '1':
                    dfs(grid, r, c)
                    res = res + 1
        
        return res

主体部分的代码非常简单,然后呢我们需要做的就是对于dfs的编写,正如在这个主体代码中写的,你会发现我这里还是用的如果box中存的元素是1,那就最终要增加岛屿数量,这难道不是错的吗?其实这里就隐喻了我们是如何完成对一个岛屿上所有的box进行标记的,与其新建一个空间例如集合然后把dfs中搜索到的box全都加入进去然后每一次循环遍历的时候去看当前的box是否在那个集合中,更好的方法其实就是直接原地更改我们的grid,将搜索到的box中的值从1修改到2,这样这个主体函数中的if 语句就不会被execute了

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:

        def dfs(grid, r, c):
            # base case, do nothing when we
            # reached the edge of entire grid or found water
            if not (0 <= r < len(grid) and 0 <= c < len(grid[0])) or grid[r][c] != '1':
                return
            
            # mark the visited box as 2
            grid[r][c] = '2'

            # call the recursive case on each direction from current box
            dfs(grid, r - 1, c)
            dfs(grid, r + 1, c)
            dfs(grid, r, c - 1)
            dfs(grid, r, c + 1)

        res = 0

        # iterate to check every box in the grid to see
        # if it is a start for a new lsland
        for r in range(len(grid)):
            for c in range(len(grid[0])):
                
                # if so, run a dfs to mark all its fellow
                # box and add the 1 to the result
                if grid[r][c] == '1':
                    dfs(grid, r, c)
                    res = res + 1
        
        return res

这样你就有了整个的代码,其实这种类型的深度优先搜索可以参考我们在二叉树的时候是怎么做的,无非也是一直遍历然后直到我们reach 到了leaf node然后发现新的node是空的时候就直接return,这里不过是多加了两个方向,在二叉树里的recursive case是对左右子节点继续call,这里是对上下左右四个横纵坐标的方向继续call,然后呢条件多加了一个,这里对应的不能超出边界就是二叉树中的if not root, 只是这里还要保证grid[r][c] == 1,不是1的话就不是我们要找的同一个岛屿上的点

时间复杂度 O(m*n):m和n就是grid的长和宽,因为我们要遍历每一个坐标

空间复杂度 O(m*n):在最坏的情况下,如果左上角的box就是陆地1,并且整张图都是1,                                       那么我们就要把每一个box都有一个recursive function,这样在就会用                                     到一个大小为m*n的栈


Leetcode 994. 腐烂的橘子

广度优先搜索法:

这道题的关键在于我们在一开始所给的grid里面存在多个橘子的可能,我们需要在把能弄腐烂的橘子全部弄完之后就返回结果,所以每一分钟里我们需要对所有当前的橘子进行扩散,这里运用深度优先的递归就很麻烦,因为我们每一次逻辑要处理多个搜索

这里我们就使用广度优先,利用队列来对腐烂橘子进行保存并且通过出队来进行遍历然后扩散后把新的腐烂的橘子继续加入队列

这样以来,每一次我们通过向四个方向的检查中发现新的好橘子之后就可以立马对其进行操作,具体分三步,第一步将其加入我们的队列代表下一轮遍历的时候,他会pop出来作为新的坐标然后向四周扩散,第二步将我们的好橘子的count做一个递减,第三步,将grid中其坐标位置的值从1变成2避免后序的遍历中反复visit这个坏橘子

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        # we are using a queue to do the bfs
        q = deque()
        fresh_count = 0
        res = 0

        # loop through the gird first to find 
        # the amount of fresh and add the rotten to
        # the queue
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == 1:
                    fresh_count = fresh_count + 1
                elif grid[i][j] == 2:
                    q.append((i, j))


        # loop until we have no more rotten orange
        while q and fresh_count > 0:

            # every time we start pop out q again, we did another search
            res = res + 1

            # for each rotten orango, pop them out
            for _ in range(len(q)):
                box = q.popleft()
                r, c = box[0], box[1]

                # check top
                if r - 1 >= 0 and grid[r - 1][c] == 1:
                    fresh_count = fresh_count - 1
                    q.append((r - 1, c))
                    grid[r - 1][c] = 2

                
                # check right
                if c + 1 < len(grid[0]) and grid[r][c + 1] == 1:
                    fresh_count = fresh_count - 1
                    q.append((r, c + 1))
                    grid[r][c + 1] = 2
                
                # check bot
                if r + 1 < len(grid) and grid[r + 1][c] == 1:
                    fresh_count = fresh_count - 1
                    q.append((r + 1, c))      
                    grid[r + 1][c] = 2

                # check left
                if c - 1 >= 0 and grid[r][c - 1] == 1:
                    fresh_count = fresh_count - 1
                    q.append((r, c - 1))
                    grid[r][c - 1] = 2
        
        # we did not get them all rotton
        if fresh_count > 0:
            return -1
        else:
            return res

时间复杂度 O(m*n):m和n就是grid的长和宽,因为我们要遍历每一个坐标

空间复杂度 O(m*n):在最坏的情况下,一开始所有的橘子都是坏橘子,我们使用的额外空间队列的长度最大就是m*n

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

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

相关文章

C#探索之路基础篇(1):编程中面向过程、数据、对象的概念辨析

文章目录 C#探索之路基础篇(1)&#xff1a;编程中面向过程、数据、对象的概念辨析1 面向过程编程1.1 概念1.2 示例代码&#xff1a;1.3 使用范围与时机&#xff1a;1.4 注意事项&#xff1a;1.5 通俗讲法 2 面向对象编程2.1 概念2.2 示例代码2.3 使用范围2.4 注意事项2.5 通俗讲…

将数据转换成xml格式的文档并下载

现在有一个实体类对象的集合&#xff0c;需要将它们转换为xml文档&#xff0c;xml文档就是标签集合的嵌套&#xff0c;例如一个学生类&#xff0c;有姓名、年龄等&#xff0c;需要转换成一下效果&#xff1a; <student><age>14</age><name>张三</na…

十、C#基数排序算法

简介 基数排序是一种非比较性排序算法&#xff0c;它通过将待排序的数据拆分成多个数字位进行排序。 实现原理 首先找出待排序数组中的最大值&#xff0c;并确定排序的位数。 从最低位&#xff08;个位&#xff09;开始&#xff0c;按照个位数的大小进行桶排序&#xff0c;将…

STL —— string(1)

目录 1. 模板 1.1 泛型编程 1.2 函数模板 1.2.1 函数模板概念 1.2.2 函数模板格式 1.2.3 函数模板的原理 1.2.4 显式实例化 1.2.5 模板参数的匹配原则 1.3 类模板 1.3.1 类模板定义格式 1.3.2 类模板的实例化 2. STL —— string类 2.1 STL 简介 2.2 标准库中的s…

地理信息数据处理-线面数据转化和数据合并(二)

需求 1.数据为LineString&#xff0c;需要转化为Polygon 2.数据为多个分散的线、面数据&#xff0c;需要转化为一条Multi类型数据 解决方案使用&#xff0c;arcgis转化工具。 需求1&#xff1a;线-面数据转化 1.在arcgis中选中对应图层&#xff0c; 然后在“数据管理工具-要…

pcl采样:随机采样

pcl 随机采样,实际上就是抽稀 头文件 代码 结果

阿里云2024最新优惠:WoSign SSL证书首购4折

阿里云SSL证书 2024 最新优惠来啦&#xff01;阿里云SSL证书新用户&#xff0c;wosign SSL证书低至4折&#xff0c;WoSign SSL提供全球信任RSA SSL证书和国密算法SM2 SSL证书&#xff01;阿里云官网官方优惠&#xff0c;需要开年采购SSL证书的用户抓紧申请这波优惠&#xff01;…

mybatis-flex入门体验(一)

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen 趁着下午的空闲时间&#xff0c;研究了一下mybatis-flex&#xff0c;看着对我还…

【php基础】输出、变量、布尔类型、字符串

php基础补充 1. 输出2.和"的区别3.变量3.1变量的命名规则3.2 两个对象指向同一个值3.3 可变变量 4.变量的作用域5. 检测变量6. 布尔类型7.字符串定义与转义8.字符串常用函数9.常量 1. 输出 echo: 输出 print: 输出&#xff0c;输出成功返回1 print_r(): 输出数组 var_dum…

HarmonyOS入门学习

HarmonyOS入门学习 前言快速入门ArkTS组件基础组件Image组件Text组件TextInput 文本输入框Buttonslider 滑动组件 页面布局循环控制ForEach循环创建组件 List自定义组件创建自定义组件Builder 自定义函数 状态管理Prop和LinkProvide和ConsumeObjectLink和Observed ArkUI页面路由…

【网络安全】CobaltStrike 使用

本文章仅用于信息安全学习&#xff0c;请遵守相关法律法规&#xff0c;严禁用于非法途径。若读者因此作出任何危害网络安全的行为&#xff0c;后果自负&#xff0c;与作者无关。 Cobalt Strike是一款渗透测试神器&#xff0c;Cobalt Strike已经不再使用MSF而是作为单独的平台使…

如何避免OKR成为形式主义,真正发挥其作用?

OKR&#xff08;Objectives and Key Results&#xff09;作为一种目标管理方法&#xff0c;旨在通过设定明确的目标和可衡量的关键成果&#xff0c;帮助企业实现高效、精准的管理。然而&#xff0c;在实际应用中&#xff0c;许多企业却陷入了形式主义的泥潭&#xff0c;使OKR失…

1.什么是exchange的自签名证书?安装exchange后,默认生成的证书介绍?如何查看exchange的证书情况?命令是?

目录 1.exchange的自签名证介绍 2.如何查看exchange的证书&#xff1f; 3.默认生成证书介绍 第一张&#xff1a;Microsoft Exchange 第二张&#xff1a;Microsoft Exchange Server Auth Certificate 第三张&#xff1a;WMSVC 总结&#xff1a; 1.exchange的自签名证介绍…

JAVA 获取系统当前时间、时间格式互相转化工具类,2024百度Java岗面试真题收录解析

DateTimeFormatter ftf DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”); LocalDateTime parse LocalDateTime.parse(strTime, ftf); return LocalDateTime.from(parse).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); } //通过LocalDateTime获取当…

CPP容器vector和list,priority_queue定义比较器

#include <iostream> #include <bits/stdc.h> using namespace std; struct VecCmp{bool operator()(int& a,int& b){return a>b;/*** 对于vector和list容器&#xff0c;这里写了&#xff1e;就是从大到小* 对于priority_queue容器&#xff0c;这里写…

YOLO改进模块出现的问题及改进方法

1.grid_sampler_2d_backward_cuda 在对YOLOv9进行改进的过程中&#xff0c;有的时候就会出现这种报错&#xff1a;RuntimeError: grid_sampler_2d_backward_cuda does not have a deterministic implementation&#xff0c;but you set torch.use_deterministic_algorithms(Tr…

【SpringSecurity】十七、OAuth2授权服务器 + 资源服务器Demo

文章目录 0、库表准备1、项目结构2、基于数据库的认证3、授权服务器配置4、授权服务器效果测试5、资源服务器配置6、其他授权模式测试6.1 密码模式6.2 简化模式6.3 客户端模式6.4 refresh_token模式 相关&#x1f4d5;&#xff1a;【Spring Security Oauth2 配置理论部分】 0、…

[C#]winformYOLO区域检测任意形状区域绘制射线算法实现

【简单介绍】 Winform OpenCVSharp YOLO区域检测与任意形状区域射线绘制算法实现 在现代安全监控系统中&#xff0c;区域检测是一项至关重要的功能。通过使用Winform结合OpenCVSharp库&#xff0c;并结合YOLO&#xff08;You Only Look Once&#xff09;算法&#xff0c;我们…

Docker之docker compose!!!!

一、概述 是 Docker 官方提供的一款开源工具&#xff0c;主要用于简化在单个主机上定义和运行多容器 Docker 应用的过程。它的核心作用是容器编排&#xff0c;使得开发者能够在一个统一的环境中以声明式的方式管理多容器应用的服务及其依赖关系。 也就是说Docker Compose是一个…

利用Jmeter工具对服务器,数据库进行性能监控,压测,导出性能测试报告

Jmeter是Apache基金会旗下的一款免费,开源,轻量级的性能测试工具,主要针对web应用程序客户端/服务器进行性能测试.它可以分别测试静态、动态资源(Java Servlet,CGI Scripts,Java Object,数据库和FTP服务器等),它可以通过线程组来模拟数个用户,在一段时间内同时登录服务器,数个用…