LeetCode之图

200. 岛屿数量

class Solution {

    public int numIslands(char[][] grid) {
        int rows = grid.length;
        int clolumns = grid[0].length;
        if (grid == null || rows == 0) {
            return 0;
        }
        int numIsLands = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < clolumns; j++) {
                if (grid[i][j] == '1') {
                    numIsLands++;
                    dfs(grid, i, j);
                }
            }
        }
        return numIsLands;
    }

    private void dfs(char[][] grid, int row, int clolumn) {
        int rows = grid.length;
        int clolumns = grid[0].length;
        if (row < 0 || clolumn < 0 || row >= rows || clolumn >= clolumns || grid[row][clolumn] == '0') {
            return;
        }
        grid[row][clolumn] = '0';
        dfs(grid, row - 1, clolumn);
        dfs(grid, row + 1, clolumn);
        dfs(grid, row, clolumn - 1);
        dfs(grid, row, clolumn + 1);
    }
}

130. 被围绕的区域

class Solution {
    int m;
    int n;

    public void solve(char[][] board) {
        // 获取二维字符数组的行数
        m = board.length;
        // 如果二维字符数组为空,直接返回
        if (m == 0) {
            return;
        }
        // 获取二维字符数组的列数
        n = board[0].length;

        // 遍历第一列和最后一列,对与边界相连的'O'进行深度优先搜索并标记为'A'
        for (int i = 0; i < m; i++) {
            dfs(board, i, 0);
            dfs(board, i, n - 1);
        }

        // 遍历第一行和最后一行的中间部分,对与边界相连的'O'进行深度优先搜索并标记为'A'
        for (int i = 0; i < n; i++) {
            dfs(board, 0, i);
            dfs(board, m - 1, i);
        }

        // 再次遍历整个二维字符数组
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 如果当前位置为'A',说明是与边界相连的'O',恢复为'O'
                if (board[i][j] == 'A') {
                    board[i][j] = 'O';
                } else {
                    // 如果当前位置为'O'且不是与边界相连的,替换为'X'
                    board[i][j] = 'X';
                }
            }
        }

    }

    private void dfs(char[][] board, int x, int y) {
        // 如果坐标越界或者当前位置不是'O',直接返回
        if (x < 0 || x >= m || y < 0 || y >= n || board[x][y]!= 'O') {
            return;
        }
        // 将当前位置标记为'A'
        board[x][y] = 'A';
        // 对上下左右四个方向进行深度优先搜索
        dfs(board, x + 1, y);
        dfs(board, x - 1, y);
        dfs(board, x, y + 1);
        dfs(board, x, y - 1);
    }
}

133. 克隆图

class Solution {
    
    // 存储已访问节点及其对应的克隆节点
    private HashMap<Node, Node> visited = new HashMap<>();

    public Node cloneGraph(Node node) {
        // 如果输入节点为空,直接返回空
        if (node == null) {
            return node;
        }

        // 如果该节点已经被访问过了,则直接从哈希表中取出对应的克隆节点返回
        if (visited.containsKey(node)) {
            return visited.get(node);
        }

        // 创建一个新的节点,值与输入节点相同,邻居列表初始为空
        Node cloneNode = new Node(node.val, new ArrayList());
        // 将输入节点和克隆节点放入哈希表中
        visited.put(node, cloneNode);

        // 遍历输入节点的邻居列表
        for (Node neighbor : node.neighbors) {
            // 递归地克隆邻居节点,并将克隆后的邻居节点添加到克隆节点的邻居列表中
            cloneNode.neighbors.add(cloneGraph(neighbor));
        }
        // 返回克隆后的节点
        return cloneNode;
    }

}

399. 除法求值

import java.util.*;

// 定义 Solution 类
class Solution {
    public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
        // 1. 创建一个图,使用嵌套 HashMap 存储每对变量之间的关系
        Map<String, Map<String, Double>> graph = new HashMap<>();
        int n = equations.size();

        // 2. 构建图
        for (int i = 0; i < n; i++) {
            String u = equations.get(i).get(0); // 第一个变量
            String v = equations.get(i).get(1); // 第二个变量
            double weight = values[i]; // 变量之间的值

            // 添加边及其反向边
            graph.putIfAbsent(u, new HashMap<>()); // 如果 u 不在图中,初始化它
            graph.putIfAbsent(v, new HashMap<>()); // 如果 v 不在图中,初始化它
            graph.get(u).put(v, weight); // u 到 v 的边
            graph.get(v).put(u, 1.0 / weight); // v 到 u 的边
        }

        // 3. 准备结果数组,默认为 -1.0(表示无解)
        int m = queries.size();
        double[] results = new double[m];
        Arrays.fill(results, -1.0);

        // 4. 对每个查询进行 BFS
        for (int i = 0; i < m; i++) {
            String start = queries.get(i).get(0); // 查询的起始变量
            String target = queries.get(i).get(1); // 查询的目标变量

            // 检查起始变量和目标变量是否存在于图中
            if (!graph.containsKey(start) || !graph.containsKey(target)) {
                continue; // 如果任一变量不存在,跳过此查询
            }

            // 处理起始变量与目标变量相同的情况
            if (start.equals(target)) {
                results[i] = 1.0;
                continue;
            }

            // 5. BFS 初始化
            Queue<Map.Entry<String, Double>> queue = new LinkedList<>();
            Map<String, Boolean> visited = new HashMap<>();
            queue.add(new AbstractMap.SimpleEntry<>(start, 1.0)); // 初始元素
            visited.put(start, true); // 标记为已访问

            // 6. BFS 遍历图
            while (!queue.isEmpty()) {
                Map.Entry<String, Double> curr = queue.poll(); // 获取当前节点
                String currVar = curr.getKey();
                double currVal = curr.getValue();

                // 7. 到达目标变量,记录结果并跳出循环
                if (currVar.equals(target)) {
                    results[i] = currVal; // 更新结果
                    break; // 找到目标,结束当前查询
                }

                // 8. 遍历邻接节点
                for (Map.Entry<String, Double> neighbor : graph.get(currVar).entrySet()) {
                    String nextVar = neighbor.getKey(); // 邻接变量
                    double nextVal = neighbor.getValue(); // 变量之间的值

                    // 如果邻接变量尚未访问,则继续 BFS
                    if (!visited.containsKey(nextVar)) {
                        visited.put(nextVar, true); // 标记已访问
                        queue.add(new AbstractMap.SimpleEntry<>(nextVar, currVal * nextVal)); // 更新路径值
                    }
                }
            }
        }

        // 9. 返回结果数组
        return results;
    }
}

207. 课程表

class Solution {
    // 存储有向图的邻接表
    List<List<Integer>> edges;
    // 记录每个节点的访问状态
    int[] visited;
    // 标记是否可以完成所有课程
    boolean valid = true;

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // 初始化邻接表,每个课程对应一个列表,存储其后续课程
        edges = new ArrayList<List<Integer>>();
        for (int i = 0; i < numCourses; ++i) {
            edges.add(new ArrayList<Integer>());
        }
        // 初始化访问状态数组,0 表示未访问,1 表示正在访问,2 表示已访问完成
        visited = new int[numCourses];
        // 根据先修课程关系构建邻接表
        for (int[] info : prerequisites) {
            edges.get(info[1]).add(info[0]);
        }
        // 遍历每个课程进行深度优先搜索
        for (int i = 0; i < numCourses && valid; ++i) {
            if (visited[i] == 0) {
                // 如果课程未被访问,进行深度优先搜索
                dfs(i);
            }
        }
        // 返回是否可以完成所有课程的标志
        return valid;
    }

    public void dfs(int u) {
        // 将当前课程标记为正在访问
        visited[u] = 1;
        // 遍历当前课程的后续课程
        for (int v : edges.get(u)) {
            if (visited[v] == 0) {
                // 如果后续课程未被访问,递归进行深度优先搜索
                dfs(v);
                if (!valid) {
                    // 如果在搜索过程中发现无法完成所有课程,直接返回
                    return;
                }
            } else if (visited[v] == 1) {
                // 如果发现后续课程正在被访问,说明存在环,无法完成所有课程
                valid = false;
                return;
            }
        }
        // 将当前课程标记为已访问完成
        visited[u] = 2;
    }
}

210. 课程表 II

class Solution {
    // 存储有向图
    List<List<Integer>> edges;
    // 标记每个节点的状态:0=未搜索,1=搜索中,2=已完成
    int[] visited;
    // 用数组来模拟栈,下标 n - 1 为栈底,0 为栈顶,存储拓扑排序结果
    int[] result;
    // 判断有向图中是否有环
    boolean valid = true;
    // 栈下标
    int index;

    public int[] findOrder(int numCourses, int[][] prerequisites) {
        edges = new ArrayList<List<Integer>>();
        // 初始化有向图,每个课程对应一个列表,存储其后续课程
        for (int i = 0; i < numCourses; ++i) {
            edges.add(new ArrayList<Integer>());
        }
        visited = new int[numCourses];
        result = new int[numCourses];
        index = numCourses - 1;
        // 根据先修课程关系构建有向图
        for (int[] info : prerequisites) {
            edges.get(info[1]).add(info[0]);
        }
        // 每次挑选一个「未搜索」的节点,开始进行深度优先搜索
        for (int i = 0; i < numCourses && valid; ++i) {
            if (visited[i] == 0) {
                dfs(i);
            }
        }
        if (!valid) {
            // 如果有环,返回空数组
            return new int[0];
        }
        // 如果没有环,那么就有拓扑排序,返回结果数组
        return result;
    }

    public void dfs(int u) {
        // 将节点标记为「搜索中」
        visited[u] = 1;
        // 搜索其相邻节点
        // 只要发现有环,立刻停止搜索
        for (int v : edges.get(u)) {
            // 如果「未搜索」那么搜索相邻节点
            if (visited[v] == 0) {
                dfs(v);
                if (!valid) {
                    return;
                }
            }
            // 如果「搜索中」说明找到了环
            else if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        // 将节点标记为「已完成」
        visited[u] = 2;
        // 将节点入栈,栈底在数组末尾,栈顶在数组开头
        result[index--] = u;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值