hot100-图论/岛屿问题

news/2024/9/24 13:18:23/

问题模板
为什么要将格子标记为【已遍历】—避免 重复遍历
(这是因为,网格结构本质上是一个「图」,我们可以把每个格子看成图中的结点,每个结点有向上下左右的四条边。在图中遍历时,自然可能遇到重复遍历结点。这时候,DFS 可能会不停地「兜圈子」,永远停不下来

void dfs(int[][] grid, int r, int c) {// 判断 base caseif (!inArea(grid, r, c)) {return;}// 如果这个格子不是岛屿,直接返回if (grid[r][c] != 1) {return;}grid[r][c] = 2; // 将格子标记为「已遍历过」// 访问上、下、左、右四个相邻结点dfs(grid, r - 1, c);dfs(grid, r + 1, c);dfs(grid, r, c - 1);dfs(grid, r, c + 1);
}// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {return 0 <= r && r < grid.length && 0 <= c && c < grid[0].length;
}

200. 岛屿数量

class Solution {public int numIslands(char[][] grid) {if(grid==null||grid.length==0)return 0;int cnt=0;int m=grid.length;int n =grid[0].length;for(int i=0;i<m;i++){for(int j=0;j<n;j++){if(grid[i][j]=='1'){cnt++;dfs(grid,i,j);}}}return cnt;}void dfs(char[][] grid, int r, int c) {// 判断 base caseif (!inArea(grid, r, c)) {return;}// 如果这个格子不是岛屿,直接返回if (grid[r][c] != '1') {return;}grid[r][c] = '2'; // 将格子标记为「已遍历过」// 访问上、下、左、右四个相邻结点dfs(grid, r - 1, c);dfs(grid, r + 1, c);dfs(grid, r, c - 1);dfs(grid, r, c + 1);}// 判断坐标 (r, c) 是否在网格中boolean inArea(char[][] grid, int r, int c) {return 0 <= r && r < grid.length && 0 <= c && c < grid[0].length;}
}

695. 岛屿的最大面积

这道题同样根据dfs模板走,只不过区别是dfs返回值变成了 1+dfs(上下左右)的面积

class Solution {public int maxAreaOfIsland(int[][] grid) {int m = grid.length;int n = grid[0].length;int max_area=0;for(int i = 0;i<m;i++){for(int j=0;j<n;j++){int temp_area=dfs(grid,i,j);max_area=Math.max(max_area,temp_area);}}return max_area;}int  dfs(int[][] grid,int r,int c){int m = grid.length;int n= grid[0].length;if(!inArea(grid,r,c))return 0;//不是岛屿 直接返回if(grid[r][c]!=1)return 0;grid[r][c]=2;return 1+dfs(grid,r-1,c)+dfs(grid,r+1,c)+dfs(grid,r,c-1)+dfs(grid,r,c+1);}boolean inArea(int[][] grid,int r,int c){return r>=0&&r<grid.length&&c>=0&&c<grid[0].length;}
}

463. 岛屿的周长

岛屿的周长是计算岛屿全部的「边缘」,而这些边缘就是我们在 DFS 遍历中,dfs 函数返回的位置。
当我们的 dfs 函数因为「坐标 (r, c) 超出网格范围」返回的时候,实际上就经过了一条黄色的边;而当函数因为「当前格子是海洋格子」返回的时候,实际上就经过了一条蓝色的边

class Solution {public int islandPerimeter(int[][] grid) {for (int r = 0; r < grid.length; r++) {for (int c = 0; c < grid[0].length; c++) {if (grid[r][c] == 1) {// 题目限制只有一个岛屿,计算一个即可return dfs(grid, r, c);}}}return 0;}int dfs(int[][] grid, int r, int c) {// 函数因为「坐标 (r, c) 超出网格范围」返回,对应一条黄色的边if (!inArea(grid, r, c)) {return 1;}// 函数因为「当前格子是海洋格子」返回,对应一条蓝色的边if (grid[r][c] == 0) {return 1;}// 函数因为「当前格子是已遍历的陆地格子」返回,和周长没关系if (grid[r][c] != 1) {return 0;}grid[r][c] = 2;return dfs(grid, r - 1, c)+ dfs(grid, r + 1, c)+ dfs(grid, r, c - 1)+ dfs(grid, r, c + 1);}// 判断坐标 (r, c) 是否在网格中boolean inArea(int[][] grid, int r, int c) {return 0 <= r && r < grid.length && 0 <= c && c < grid[0].length;}
}

另一类bfs问题

994. 腐烂的橘子

想象以污染的橘子为污染源,然后将相邻的橘子一层一层污染,考虑BFS

class Solution{
public int orangesRotting(int[][] grid) {int M = grid.length;int N = grid[0].length;Queue<int[]> queue = new LinkedList<>();int count = 0; // count 表示新鲜橘子的数量for (int r = 0; r < M; r++) {for (int c = 0; c < N; c++) {if (grid[r][c] == 1) {count++;} //一开始,我们找出所有腐烂的橘子,将它们放入队列,作为第 0 层的结点。//就是污染源else if (grid[r][c] == 2) {queue.add(new int[]{r, c});}}}int round = 0; // round 表示腐烂的轮数,或者分钟数while (count > 0 && !queue.isEmpty()) {round++;int n = queue.size();for (int i = 0; i < n; i++) {int[] orange = queue.poll();int r = orange[0];int c = orange[1];//将相邻方向依次污染if (r-1 >= 0 && grid[r-1][c] == 1) {grid[r-1][c] = 2;count--;queue.add(new int[]{r-1, c});}if (r+1 < M && grid[r+1][c] == 1) {grid[r+1][c] = 2;count--;queue.add(new int[]{r+1, c});}if (c-1 >= 0 && grid[r][c-1] == 1) {grid[r][c-1] = 2;count--;queue.add(new int[]{r, c-1});}if (c+1 < N && grid[r][c+1] == 1) {grid[r][c+1] = 2;count--;queue.add(new int[]{r, c+1});}}}if (count > 0) {return -1;} else {return round;}
}
}

207. 课程表

class Solution {public boolean canFinish(int numCourses, int[][] prerequisites) {//判断是否是有向无环图-------》拓扑排序//通过课程前置条件列表 prerequisites 可以得到课程安排图的 邻接表 adjacency//统计课程安排图中每个节点的入度,生成 入度表 indegrees。//借助一个队列 queue,将所有入度为 0 的节点入队。//拓扑排序过程//删顶点 再把顶点的出边删掉,即对应所有邻接节点的入度-1//当入度 −1后邻接节点 cur 的入度为 0,说明 cur 所有的前驱节点已经被 “删除”,//此时将 cur 入队。int[] indegree = new int[numCourses];List<List<Integer>> adjacent  = new ArrayList<>();Queue<Integer> list = new LinkedList<>();for(int i=0;i<numCourses;i++)adjacent.add(new ArrayList<>());for(int[] tmp : prerequisites) {indegree[tmp[0]]++;adjacent.get(tmp[1]).add(tmp[0]);}//将所以入度为0的节点入队for(int i=0;i<numCourses;i++){if(indegree[i]==0)list.add(i);}//排序过程while(!list.isEmpty()){int pre =list.poll();numCourses--;//他的邻接节点入度--for(int tmp :adjacent.get(pre)){indegree[tmp]--;if(indegree[tmp]==0)list.add(tmp);}}return numCourses==0;}
}

208. 实现 Trie (前缀树)


class Trie {class TrieNode{private boolean isEnd;TrieNode[] next;public TrieNode() {isEnd = false;next= new TrieNode[26];}}private TrieNode root;public Trie(){root = new TrieNode();}public void insert(String word) {TrieNode node = root;for(char c : word.toCharArray()){if(node.next[c-'a']==null)node.next[c-'a']=new TrieNode();node=node.next[c-'a'];}node.isEnd = true;}public boolean search(String word) {TrieNode node = root;for(char c :word.toCharArray()){if(node.next[c-'a']==null){return false;}node=node.next[c-'a'];}return node.isEnd;}public boolean startsWith(String prefix) {TrieNode node = root;for(char c :prefix.toCharArray()){if(node.next[c-'a']==null){return false;}node=node.next[c-'a'];}return true;}
}

注意 startwith和search的区别
startwith 走完prefix循环就可以返回true;
而search走完循环还要看是不是到最终的叶结点了
不然 比如word为prefix 而树中是prefixxx 也会错误的search为true


http://www.ppmy.cn/news/1426003.html

相关文章

JS - 分支结构、循环结构

关于JavaScript中的分支结构和循环结构&#xff0c;其实和其他编程语言区别也不是很大&#xff0c;只是js对这两种结构进行了相应的扩充&#xff0c;当然本质上并没有变化&#xff0c;本篇就是一篇记录博主在学习前端路上的总结和敲过的demo&#xff0c;实际上水份很大&#xf…

C++实战——日期类的实现

日期类的实现 前言一、日期类概念实现运用场景 二、日期类的具体实现代码构造函数拷贝构造函数获取日期&#xff08;内联函数&#xff09;赋值加等减等加减小于小于等于大于大于等于相等不相等前置后置前置- -后置- -关于类里重载的比较运算符为什么要加外部const示例 Date.hDa…

matlab多核程序如何共享内存和数据

在MATLAB中&#xff0c;多核程序共享内存和数据主要依赖于MATLAB的并行计算工具箱&#xff08;Parallel Computing Toolbox&#xff09;。这个工具箱提供了多种机制来在多个工作进程&#xff08;workers&#xff09;之间共享数据&#xff0c;这些工作进程可能运行在同一台机器的…

用mySql设计一个在线简易在线交易平台数据库

设计需求 当设计一个在线交易商店的数据库架构时&#xff0c;需要考虑多个方面&#xff0c;包括产品信息、订单管理、用户信息、支付信息等。以下是一个简单的数据库架构示例&#xff1a; 产品信息表 (Products) ProductID (主键)ProductNameDescriptionPriceStockQuantity 订…

利用vue3SeamlessScroll 简单实现列表的无限循环滚动

Vue3SeamlessScroll 该组件用于实现列表的无限循环滚动 1、安装 npm i vue3-seamless-scroll 2、导入及基本使用 <!--组件.vue--> <script setup>import { Vue3SeamlessScroll } from vue3-seamless-scroll;import {ref} from vue//vue3导入组件是不需要用com…

MacOS Github Push项目 精简版步骤

大白菜教程&#xff1a;小白菜 macOS github提交代码-CSDN博客 步骤1&#xff1a;git init步骤2&#xff1a; touch .gitignore 创建ignore文件 open .gitignore 打开ignore文件 编写ignore文件.idea/ 是文件夹的意思.git/ 也是自动生成的文件夹 也不上传.DS_St…

Day07 React——第七天 (18新特性 hook)

React 18引入了hooks&#xff0c;这是一种让函数组件拥有类组件的功能的方式。使用hooks&#xff0c;函数组件可以拥有状态管理、生命周期方法、副作用处理等功能&#xff0c;使得函数组件具有了和类组件类似的能力。hooks可以让函数组件更加灵活和易于管理&#xff0c;同时也减…