您的位置:首页 > 汽车 > 新车 > 【LeetCode 随笔】面试经典 150 题【中等+困难】持续更新中。。。

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

2025/1/6 17:45:31 来源:https://blog.csdn.net/shiranyyds/article/details/139210774  浏览:    关键词:【LeetCode 随笔】面试经典 150 题【中等+困难】持续更新中。。。

文章目录

    • 76.【困难】最小覆盖子串
    • 36.【中等】有效的数独
    • 54.【中等】螺旋矩阵
    • 48.【中等】旋转图像
    • 73.【中等】矩阵置零

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

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;  }  }  }  }  
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com