【LeetCode 随笔】面试经典 150 题【中等+困难】持续更新中。。。

🌈你好呀!我是 山顶风景独好
💝欢迎来到我的博客,很高兴能够在这里和您见面!
💝希望您在这里可以感受到一份轻松愉快的氛围!
💝不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
🚀 欢迎一起踏上探险之旅,挖掘无限可能,共同成长!

76.【困难】最小覆盖子串

  • 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
    注意:
  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 :

  • 输入:s = “ADOBECODEBANC”, t = “ABC”
  • 输出:“BANC”
  • 解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。
class Solution {  
   // 定义一个公共方法,用于找到包含t的最短子串  
   public String minWindow(String S, String t) {  
       // 将S转换为字符数组,方便后续操作  
       char[] s = S.toCharArray();  
       int m = s.length; // S的长度  
 
       // 初始化答案的左右边界,初始值使得最后返回的字符串为空字符串  
       int ansLeft = -1;  
       int ansRight = m;  
 
       // 定义滑动窗口的左边界  
       int left = 0;  
 
       // less表示在t中但当前在s的窗口中出现次数还不足的字符数量  
       int less = 0;  
 
       // 初始化两个数组,用于记录s和t中每个字符的出现次数  
       int[] cntS = new int[128]; // s 子串字母的出现次数  
       int[] cntT = new int[128]; // t 中字母的出现次数  
 
       // 遍历t中的每个字符,初始化cntT数组和less变量  
       for (char c : t.toCharArray()) {  
           if (cntT[c]++ == 0) {  
               less++; // 如果t中某个字符第一次出现,则less加1  
           }  
       }  
 
       // 遍历S,通过移动右边界来扩展窗口  
       for (int right = 0; right < m; right++) { // 移动子串右端点  
           char c = s[right]; // 右端点字母(移入子串)  
 
           // 如果s中当前字符c的出现次数增加到与t中相同,说明less可以减1  
           if (++cntS[c] == cntT[c]) {  
               less--; // c 的出现次数从 < 变成 >=  
           }  
 
           // 当窗口内的字符都满足在t中的出现次数时(less == 0),尝试收缩窗口  
           while (less == 0) { // 涵盖:所有字母的出现次数都是 >=  
               // 如果当前窗口比之前的答案更短,则更新答案  
               if (right - left < ansRight - ansLeft) { // 找到更短的子串  
                   ansLeft = left; // 记录此时的左右端点  
                   ansRight = right;  
               }  
 
               // 移动左边界,尝试缩小窗口  
               char x = s[left++]; // 左端点字母(移出子串)  
 
               // 如果移出的字符x在s中的出现次数小于t中,说明less需要加1  
               if (cntS[x]-- == cntT[x]) {  
                   less++; // x 的出现次数从 >= 变成 <  
               }  
 
               // 当less不再为0时,说明窗口内已不满足包含t的所有字符,退出循环  
           }  
       }  
 
       // 如果ansLeft仍然为-1,说明S中不包含t,返回空字符串;否则返回最短子串  
       return ansLeft < 0 ? "" : S.substring(ansLeft, ansRight + 1);  
   }  
}

36.【中等】有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

  • 数字 1-9 在每一行只能出现一次。
  • 数字 1-9 在每一列只能出现一次。
  • 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 空白格用 ‘.’ 表示。

示例 1:
在这里插入图片描述

  • 输入:board =
    [[“5”,“3”,“.”,“.”,“7”,“.”,“.”,“.”,“.”]
    ,[“6”,“.”,“.”,“1”,“9”,“5”,“.”,“.”,“.”]
    ,[“.”,“9”,“8”,“.”,“.”,“.”,“.”,“6”,“.”]
    ,[“8”,“.”,“.”,“.”,“6”,“.”,“.”,“.”,“3”]
    ,[“4”,“.”,“.”,“8”,“.”,“3”,“.”,“.”,“1”]
    ,[“7”,“.”,“.”,“.”,“2”,“.”,“.”,“.”,“6”]
    ,[“.”,“6”,“.”,“.”,“.”,“.”,“2”,“8”,“.”]
    ,[“.”,“.”,“.”,“4”,“1”,“9”,“.”,“.”,“5”]
    ,[“.”,“.”,“.”,“.”,“8”,“.”,“.”,“7”,“9”]]
  • 输出:true

示例 2:

  • 输入:board =
    [[“8”,“3”,“.”,“.”,“7”,“.”,“.”,“.”,“.”]
    ,[“6”,“.”,“.”,“1”,“9”,“5”,“.”,“.”,“.”]
    ,[“.”,“9”,“8”,“.”,“.”,“.”,“.”,“6”,“.”]
    ,[“8”,“.”,“.”,“.”,“6”,“.”,“.”,“.”,“3”]
    ,[“4”,“.”,“.”,“8”,“.”,“3”,“.”,“.”,“1”]
    ,[“7”,“.”,“.”,“.”,“2”,“.”,“.”,“.”,“6”]
    ,[“.”,“6”,“.”,“.”,“.”,“.”,“2”,“8”,“.”]
    ,[“.”,“.”,“.”,“4”,“1”,“9”,“.”,“.”,“5”]
    ,[“.”,“.”,“.”,“.”,“8”,“.”,“.”,“7”,“9”]]
  • 输出:false
  • 解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
class Solution {  
    public boolean isValidSudoku(char[][] board) {  
        // 初始化9x9的行标记数组,用于记录每行中每个数字出现的次数  
        int[][] rows = new int[9][9];  
        // 初始化9x9的列标记数组,用于记录每列中每个数字出现的次数  
        int[][] columns = new int[9][9];  
        // 初始化3x3x9的子盒子标记数组,用于记录每个3x3子盒子中每个数字出现的次数  
        int[][][] subboxes = new int[3][3][9];  
  
        // 遍历9x9的棋盘  
        for (int i = 0; i < 9; i++) {  
            for (int j = 0; j < 9; j++) {  
                // 获取当前位置的字符  
                char c = board[i][j];  
  
                // 如果当前位置不是空('.'表示空)  
                if (c != '.') {  
                    // 将字符转换为数字索引('1'-'0' = 1, '2'-'0' = 2, ..., '9'-'0' = 8)  
                    // 然后减1,因为数组索引是从0开始的  
                    int index = c - '0' - 1;  
  
                    // 在当前行中标记该数字出现一次  
                    rows[i][index]++;  
  
                    // 在当前列中标记该数字出现一次  
                    columns[j][index]++;  
  
                    // 计算当前位置所属的3x3子盒子的索引  
                    // i/3 和 j/3 分别表示子盒子的行和列索引(0-2)  
                    // 然后在该子盒子中标记该数字出现一次  
                    subboxes[i / 3][j / 3][index]++;  
  
                    // 检查当前行、列和子盒子中是否有数字重复出现(即出现次数大于1)  
                    // 如果有,则返回false,表示这不是一个有效的数独  
                    if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[i / 3][j / 3][index] > 1) {  
                        return false;  
                    }  
                }  
            }  
        }  
  
        // 如果遍历完整个棋盘都没有发现重复的数字,则返回true,表示这是一个有效的数独  
        return true;  
    }  
}

54.【中等】螺旋矩阵

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:
在这里插入图片描述

  • 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
  • 输出:[1,2,3,6,9,8,7,4,5]

示例 2:
在这里插入图片描述

  • 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
  • 输出:[1,2,3,4,8,12,11,10,9,5,6,7]
class Solution {  
    public List<Integer> spiralOrder(int[][] matrix) {  
        // 创建一个空的ArrayList,用于存储遍历到的元素  
        List<Integer> order = new ArrayList<Integer>();  
        // 检查输入的矩阵是否为空或者没有行/列,若是则直接返回空列表  
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {  
            return order;  
        }  
        // 获取矩阵的行数和列数  
        int rows = matrix.length, columns = matrix[0].length;  
        // 初始化矩阵的四个边界(左、右、上、下)  
        int left = 0, right = columns - 1, top = 0, bottom = rows - 1;  
  
        // 当左边界小于等于右边界且上边界小于等于下边界时,继续遍历  
        while (left <= right && top <= bottom) {  
            // 从左到右遍历上边界  
            for (int column = left; column <= right; column++) {  
                order.add(matrix[top][column]); // 将当前元素添加到结果列表中  
            }  
  
            // 从上到下遍历右边界(注意,从top+1开始,因为上边界已经遍历过了)  
            for (int row = top + 1; row <= bottom; row++) { // 从top+1开始,避免重复添加上边界的元素  
                order.add(matrix[row][right]); // 将当前元素添加到结果列表中  
            }  
  
            // 如果内部还有未遍历的元素(即不是只有一行或一列的情况)  
            if (left < right && top < bottom) {  
                // 从右到左遍历下边界(注意,从right-1开始,因为右边界已经遍历过了)  
                for (int column = right - 1; column > left; column--) { // 从right-1开始,避免重复添加右边界的元素  
                    order.add(matrix[bottom][column]); // 将当前元素添加到结果列表中  
                }  
  
                // 从下到上遍历左边界(注意,此时bottom和left的边界已经更新,可以安全遍历)  
                for (int row = bottom; row > top; row--) { // 从bottom开始,避免重复添加下边界的元素  
                    order.add(matrix[row][left]); // 将当前元素添加到结果列表中  
                }  
            }  
  
            // 更新四个边界,向内缩小一圈  
            left++;  
            right--;  
            top++;  
            bottom--;  
        }  
  
        // 返回遍历后的结果列表  
        return order;  
    }  
}

48.【中等】旋转图像

  • 给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
  • 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 :
在这里插入图片描述

  • 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
  • 输出:[[7,4,1],[8,5,2],[9,6,3]]
class Solution {  
    public void rotate(int[][] matrix) {  
        // 获取矩阵的行数(也是列数,因为矩阵是方阵)  
        int n = matrix.length;  
  
        // 外层循环,每次处理矩阵的一个“圈”。  
        // 因为矩阵是n*n的,所以只需要处理到n/2即可(包含中间那行/列如果n是奇数)  
        for (int i = 0; i < n / 2; i++) {  
            // 内层循环,每次处理当前“圈”的一行。  
            // 因为矩阵是对称的,所以只需要处理到(n+1)/2即可(当n是奇数时,中间的列已经在外层循环中处理过了)  
            for (int j = 0; j < (n + 1) / 2; j++) {  
                // 暂存matrix[i][j]的值  
                int tmp = matrix[i][j];  
  
                // 顺时针旋转90度,替换matrix[i][j]为右下角的值  
                matrix[i][j] = matrix[n - 1 - j][i];  
  
                // 替换右下角的值为左下角的值  
                matrix[n - 1 - j][i] = matrix[n - 1 - i][n - 1 - j];  
  
                // 替换左下角的值为左上角的值  
                matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i];  
  
                // 替换左上角的值为暂存的值(即原matrix[i][j]的值),完成一个顺时针90度的旋转  
                matrix[j][n - 1 - i] = tmp;  
            }  
        }  
    }  
}

73.【中等】矩阵置零

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

示例 1:
在这里插入图片描述

  • 输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
  • 输出:[[1,0,1],[0,0,0],[1,0,1]]

示例 2:
在这里插入图片描述

  • 输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
  • 输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]
class Solution {  
    public void setZeroes(int[][] matrix) {  
        // 获取矩阵的行数和列数  
        int m = matrix.length;           // 矩阵的行数  
        int n = matrix[0].length;        // 矩阵的列数(假设矩阵不为空)  
  
        // 定义两个布尔数组,用于记录每一行和每一列是否含有0  
        boolean[] row = new boolean[m];   // 标记行是否有0  
        boolean[] col = new boolean[n];   // 标记列是否有0  
  
        // 遍历矩阵,检查每一元素是否为0,并设置对应行和列的标记  
        for (int i = 0; i < m; i++) {  
            for (int j = 0; j < n; j++) {  
                if (matrix[i][j] == 0) {  
                    // 如果找到0,则标记当前行和当前列为有0  
                    row[i] = true;  
                    col[j] = true;  
                }  
            }  
        }  
  
        // 再次遍历矩阵,根据行和列的标记,将对应位置的元素置为0  
        for (int i = 0; i < m; i++) {  
            for (int j = 0; j < n; j++) {  
                // 如果当前行或当前列被标记为有0,则置当前位置为0  
                if (row[i] || col[j]) {  
                    matrix[i][j] = 0;  
                }  
            }  
        }  
    }  
}
  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值