Leecode热题100中图论章节
200. 岛屿数量
// 图论 dfs
// leecode题解中nettee的岛屿问题系列通用解法
class Solution {
public int numIslands(char[][] grid) {
int res = 0; // 记录找到的岛屿数量
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
// 找到 1 ,res加1,同时淹没这个岛屿
if(grid[i][j] == '1'){
res++;
dfs(grid, i, j);
}
}
}
return res;
}
void dfs(int[][] grid, int r, int c) {
// 判断 base case
if (!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;
}
}
994. 腐烂的橘子
// leecode题解里nettee的解法
// 求腐烂橘子到所有新鲜橘子的最短路径 使用 BFS
class Solution {
public int orangesRotting(int[][] grid) {
Queue<int[]> queue = new LinkedList<>();
int count = 0; // 表示新鲜橘子的数量
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
if(grid[i][j] == 1){
count++;
}else if(grid[i][j] == 2){
queue.add(new int[]{i, j});
}
}
}
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 < grid.length && 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 < grid[0].length && 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;
}
}
}
// 解题思路
// 1. 一开始,我们找出所有腐烂的橘子,将它们放入队列,作为第 0 层的结点。
// 2. 然后进行 BFS 遍历,每个结点的相邻结点可能是上、下、左、右四个方向的结点,注意判断结点位于网格边界的特殊情况。
// 3. 由于可能存在无法被污染的橘子,我们需要记录新鲜橘子的数量。在 BFS 中,每遍历到一个橘子(污染了一个橘子),就将新鲜橘子的数量减一。如果 BFS 结束后这个数量仍未减为零,说明存在无法被污染的橘子。
207. 课程表
解题思路
本题可约化为: 判断课程安排图是否是 有向无环图(DAG)
通过DFS判断图中是否有环
// leecode题解中Krahets的DFS解法
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<List<Integer>> adjacency = new ArrayList<>();
for(int i = 0; i < numCourses; i++)
adjacency.add(new ArrayList<>());
int[] flags = new int[numCourses];
for(int[] cp : prerequisites)
adjacency.get(cp[1]).add(cp[0]);
for(int i = 0; i < numCourses; i++)
if(!dfs(adjacency, flags, i)) return false;
return true;
}
private boolean dfs(List<List<Integer>> adjacency, int[] flags, int i) {
if(flags[i] == 1) return false;
if(flags[i] == -1) return true;
flags[i] = 1;
for(Integer j : adjacency.get(i))
if(!dfs(adjacency, flags, j)) return false;
flags[i] = -1;
return true;
}
}
208. 实现 Trie (前缀树)
26叉树的建立和查询
class Trie {
// 26个指向下一个节点的指针,如果表示的字母在字符串中有下一个字母,就指向代表下一个字母的node节点
// 没有 则指向为NULL
private Trie[] children;
private boolean isEnd; // 表示当前字母是否是某个字符串的结尾
public Trie() {
children = new Trie[26];
isEnd = false;
}
public void insert(String word) {
Trie node = this; // 初始化根节点
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
int index = ch - 'a';
// 插入节点 先看看当前node是否已经有指向该字母的next指针
// 如果没有 则新建一个节点
if (node.children[index] == null) {
node.children[index] = new Trie();
}
// 无论是新建还是已经指向该字母的next指针
// 当前node移动到该字母节点
node = node.children[index];
}
// 如果此时的字母是插入的字符串的最后一个
// 标记isEnd为true 表示该字母在某一个字符串里面是结束字母
node.isEnd = true;
}
// 查询就是 从根节点开始能够依次查找字符串中的字母
// 并且最后一个字母有标记结束,那么就说明之前trie树有记录同样的字符串
public boolean search(String word) {
Trie node = searchPrefix(word);
return node != null && node.isEnd;
}
// 查询前缀和查询是否保存有同样的字符串的思路是一样的
// 唯一的区别在于 查询的字母是不是某个字符串的结尾并不做要求
public boolean startsWith(String prefix) {
return searchPrefix(prefix) != null;
}
private Trie searchPrefix(String prefix) {
Trie node = this;
for (int i = 0; i < prefix.length(); i++) {
char ch = prefix.charAt(i);
int index = ch - 'a';
if (node.children[index] == null) {
return null;
}
node = node.children[index];
}
return node;
}
}