小哆啦解题记:矩阵置零大作战

3 阅读3分钟

小哆啦开始刷力扣的第三十天

73. 矩阵置零 - 力扣(LeetCode)

🌟 小哆啦与大雄的矩阵危机

一天,大雄慌慌张张地跑到小哆啦家:“哆啦,糟了!老师让我处理一个矩阵,只要有 0,就要把整行整列全都变成 0!我头都大了!”

小哆啦拍着胸脯:“区区小问题,交给我吧!”

大雄:“不过老师还说,得原地修改矩阵,不能用额外空间……”

小哆啦一听,眉头皱了皱:“原地修改?看来这次不能乱来,得好好想想。”


🚀 第一步:暴力解法

小哆啦挥动竹蜻蜓,从抽屉里掏出笔记本:“暴力解法最简单,我们先标记哪些行和列要被置零,再二次遍历矩阵,把这些行列全设成 0!”

代码刷刷写下:

function setZeroes(matrix: number[][]): void {
  const m = matrix.length;
  const n = matrix[0].length;
  const rows = new Array(m).fill(false);
  const cols = new Array(n).fill(false);

  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (matrix[i][j] === 0) {
        rows[i] = true;
        cols[j] = true;
      }
    }
  }

  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (rows[i] || cols[j]) {
        matrix[i][j] = 0;
      }
    }
  }
}

大雄看着代码拍手叫好:“哆啦,你真棒!不过……这个空间复杂度是 O(m + n),是不是有点奢侈?”

小哆啦挠挠头:“嗯……确实有点浪费,我们来优化!”


🎯 第二步:空间压缩,一维标记

小哆啦冥思苦想了一会儿:“不如我们直接复用矩阵的第一行和第一列来做标记位!这就不用额外的空间了!”

于是,他写下了第二版代码:

function setZeroes(matrix: number[][]): void {
  const m = matrix.length;
  const n = matrix[0].length;
  let firstRowZero = false;
  let firstColZero = false;

  for (let j = 0; j < n; j++) {
    if (matrix[0][j] === 0) firstRowZero = true;
  }

  for (let i = 0; i < m; i++) {
    if (matrix[i][0] === 0) firstColZero = true;
  }

  for (let i = 1; i < m; i++) {
    for (let j = 1; j < n; j++) {
      if (matrix[i][j] === 0) {
        matrix[i][0] = 0;
        matrix[0][j] = 0;
      }
    }
  }

大雄点点头:“用第一行和第一列来标记要置零的行列,这样额外空间就只用了两个布尔变量。”

小哆啦:“没错,不过还没完呢!”


🌟 第三步:最终优化

小哆啦继续优化逻辑:“最后,我们再根据第一行和第一列的标记,把真正的行列置零。”

  for (let i = 1; i < m; i++) {
    for (let j = 1; j < n; j++) {
      if (matrix[i][0] === 0 || matrix[0][j] === 0) {
        matrix[i][j] = 0;
      }
    }
  }

  if (firstRowZero) {
    for (let j = 0; j < n; j++) matrix[0][j] = 0;
  }

  if (firstColZero) {
    for (let i = 0; i < m; i++) matrix[i][0] = 0;
  }
}

大雄高兴地跳起来:“哆啦,你真是天才!时间复杂度还是 O(mn),但空间复杂度直接降到了 O(1)!”

小哆啦得意地笑了:“这就是‘空间压缩策略’!用现有资源解决问题,是不是很酷?”

总结

在这次的矩阵置零挑战中,小哆啦通过巧妙的空间压缩和优化,成功地将暴力解法的空间复杂度从 O(m + n) 降到了 O(1),而时间复杂度保持在 O(mn) 不变。这不仅展示了如何通过有效利用现有资源来优化算法,还强调了在面对实际问题时,解决方案的空间效率同样重要。小哆啦的解法证明了,编程不仅仅是写出能解决问题的代码,更重要的是思考如何在保证正确性的前提下,做到更加高效和节省资源。