LeetCode热题100记录-【矩阵、图论】

发布于:2025-04-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

矩阵

73.矩阵置零
思考:对于行和列分别用两个标记数组,遍历数组如果发现对应行列有0,则标记为true,再遍历一次将标记为true的行列元素全部置为0
记录:需要二刷

class Solution {
    public void setZeroes(int[][] matrix) {
        boolean[] row = new boolean[matrix.length];
        boolean[] col = new boolean[matrix[0].length];
        for(int i = 0;i < matrix.length;i++){
            for(int j = 0;j < matrix[0].length;j++){
                if(matrix[i][j] == 0){
                    row[i] = true;
                    col[j] = true;
                }
            }
        }
        for(int i = 0;i < matrix.length;i++){
            for(int j = 0;j < matrix[0].length;j++){
                if(row[i] || col[j]){
                    matrix[i][j] = 0;
                }
            }
        }
    }
}

54.螺旋矩阵
思考:四个角就是四个边界值,框住,依次遍历
记录:需要二刷

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        int left = 0,right = matrix[0].length-1;
        int upper = 0,lower = matrix.length-1;
        List<Integer> res = new ArrayList<>();
        while(res.size() < matrix.length * matrix[0].length){
            if(upper <= lower){
                for(int i = left;i <= right;i++){
                    res.add(matrix[upper][i]);
                }
                upper++;
            }
            if(left <= right){
                for(int i = upper;i <= lower;i++){
                    res.add(matrix[i][right]);
                }
                right--;
            }
            if(upper <= lower){
                for(int i = right;i >= left;i--){
                    res.add(matrix[lower][i]);
                }
                lower--;
            }
            if(left <= right){
                for(int i = lower;i >= upper;i--){
                    res.add(matrix[i][left]);
                }
                left++;
            }
        }
        return res;
    }
}

48.旋转图像
思考:旋转90度,相当于先按对角线翻转,再依次行翻转,记住规律就行
记录:需要二刷

class Solution {
    public void rotate(int[][] matrix) {
        for(int i = 0;i < matrix.length;i++){
            for(int j = i;j < matrix[0].length;j++){
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        for(int[] num : matrix){
            reverse(num);
        }
    }
    void reverse(int[] num){
        int left = 0,right = num.length-1;
        while(left < right){
            int temp = num[left];
            num[left] = num[right];
            num[right] = temp;
            left++;
            right--;
        }
    }
}

240.搜索二维矩阵||
思考:跟二分查找的思路一样,要找到增加、减少的条件,二维把初始定位在右上角,这样向下就是增大,向左就是减少,就可以用二分查找了
记录:不需要二刷

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int row = 0,col = matrix[0].length-1;
        while(row <= matrix.length-1 && col >= 0){
            if(matrix[row][col] < target){
                row++;
            }else if(matrix[row][col] > target){
                col--;
            }else{
                return true;
            }
        }
        return false;
    }
}

图论

200.岛屿数量
思考:遇到一个小1就把它变成小0,并且把它四周的都感染成0,经典题,秒
记录:不需要二刷

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++){
                if(grid[i][j] == '1'){
                    dfs(grid,i,j);
                    res++;
                }
            }
        }
        return res;
    }
    void dfs(char[][] grid,int i,int j){
        if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length){
            return;
        }
        if(grid[i][j] == '0'){
            return;
        }
        grid[i][j] = '0';
        dfs(grid,i+1,j);
        dfs(grid,i-1,j);
        dfs(grid,i,j+1);
        dfs(grid,i,j-1);
    }
}

994.腐烂的橘子
思考:标准BFS

  • 首先遍历一遍矩阵,将所有腐烂的橘子的坐标放到队列里
  • 然后遍历这个腐烂橘子队列,遍历的时候按照层序遍历,一边遍历一边检查它的四周如果是好橘子就把它变腐烂,然后把这个腐烂的橘子再加到队列里。注意这里方向dirs的用法
  • 最后遍历完回过去检查是否还有好橘子,如果有证明这个橘子不会被腐烂,返回-1
  • 如果没有,就返回res-1
    记录:需要二刷
class Solution {
    public int orangesRotting(int[][] grid) {
        int res = 0;
        Queue<int[]> q = new LinkedList<>();
        for(int i = 0;i < grid.length;i++){
            for(int j = 0;j < grid[0].length;j++){
                if(grid[i][j] == 2){
                    q.offer(new int[]{i,j});
                }
            }
        }
        int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
        while(!q.isEmpty()){
            int size = q.size();
            for(int i = 0;i < size;i++){
                int[] cur = q.poll();
                for(int[] dir : dirs){
                    int x = cur[0] + dir[0];
                    int y = cur[1] + dir[1];
                    if(x >= 0 && y >= 0 && x < grid.length && y < grid[0].length && grid[x][y] == 1){
                        grid[x][y] = 2;
                        q.offer(new int[]{x,y});
                    }
                }
            }
            res++;
        }
         for(int i = 0;i < grid.length;i++){
            for(int j = 0;j < grid[0].length;j++){
                if(grid[i][j] == 1){
                    return -1;
                }
            }
        }
        return res == 0 ? 0 : res-1;
    }
}

207.课程表
思考:题目本质是判断有没有循环依赖,即检查图结构是否有环
记录:需要二刷

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<Integer>[] graph = buildGraph(numCourses,prerequisites);
        onPath = new boolean[numCourses];
        visited = new boolean[numCourses];
        for(int i = 0;i < numCourses;i++){
            traverse(graph,i);
        }
        return !hasCycle;
    }
    boolean[] onPath;
    boolean[] visited;
    boolean hasCycle = false;

    void traverse(List<Integer>[] graph,int s){
        if(hasCycle){
            return;
        }
        if(onPath[s]){
            hasCycle = true; //s在递归路径上,成环
            return;
        }
        if(visited[s]){
            return;
        }
        visited[s] = true;
        onPath[s] = true;
        for(int i : graph[s]){
            traverse(graph,i);
        }
        onPath[s] = false;
    }

    List<Integer>[] buildGraph(int numCourses,int[][] prerequisites){
        List<Integer>[] graph = new LinkedList[numCourses];
        for(int i = 0;i < numCourses;i++){
            graph[i] = new LinkedList<>();
        }
        for(int[] edge : prerequisites){
            int from = edge[1],to = edge[0];
            graph[from].add(to);
        }
        return graph;
    }

}

208.实现Trie(前缀树)
思考:不会,背题解

  • 结构:每个节点表示一个字符,从根节点到某一节点的路径构成一个字符串,会用isEnd标记某个节点是否完整单词的结尾
  • 操作原理:插入(逐个字符遍历,为每个字符创建路径),查找(沿着字符路径走,检查能否完整匹配最后节点被标记为单词结尾),前缀检查(确认沿着路径走到前缀的最后一个字符)

记录:需要二刷

class Trie {
    //定义TrieNode内部类
    private class TrieNode{
        private TrieNode[] children; //子节点数组,每个索引对应一个字符
        private boolean isEnd;       //标记是否是单词结尾
        public TrieNode(){
            children = new TrieNode[26];
            isEnd = false;
        }
    }

    private TrieNode root;  //Trie的根节点

    public Trie() {
        root = new TrieNode();
    }
    
    public void insert(String word) {
        TrieNode node = root;
        for(char c : word.toCharArray()){
            int index = c - 'a';  //计算字符对应的索引
            if(node.children[index] == null){
                //该字符路径不存在,就创建新节点
                node.children[index] = new TrieNode();
            }
            node = node.children[index]; //移动到下一个节点
        }
        node.isEnd = true; //标记该节点为单词结尾
    }
    
    public boolean search(String word) {
        TrieNode node = searchPrefix(word);
        return node != null && node.isEnd;
    }
    
    public boolean startsWith(String prefix) {
        return searchPrefix(prefix) != null;
    }

    //查找前缀
    private TrieNode searchPrefix(String prefix){
        TrieNode node = root;
        for(char c : prefix.toCharArray()){
            int index = c - 'a';
            if(node.children[index] == null){
                return null; //路径不存在就返回null
            }
            node = node.children[index]; //继续向下找
        }
        return node; //返回找到的节点
    }
}