leetcode 有效的数独

147 阅读3分钟

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

数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

上图是一个部分填充的有效的数独。

数独部分空格内已填入了数字,空白格用 '.' 表示。

示例 1:

输入:
[  ["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:

输入:
[  ["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 存在, 因此这个数独是无效的。 说明:

一个有效的数独(部分已被填充)不一定是可解的。 只需要根据以上规则,验证已经填入的数字是否有效即可。 给定数独序列只包含数字 1-9 和字符 '.' 。 给定数独永远是 9x9 形式的。

我进行了两次,没想到第二次比第一次还慢:

/**
 * @param {character[][]} board
 * @return {boolean}
 */
var isValidSudoku = function (board) {
  // 第一种思路就是根据三点规则,一条一条的验证,看是否满足
  // 看规则一:数字 1-9 在每一行只能出现一次。
  let rule1Obj = {};
  for (let i = 0; i < 9; i++) {
    for (let j = 0; j < 9; j++) {
      const digit = board[i][j] - 0;
      if (digit) {
        if (rule1Obj[digit]) {
          return false;
        }
        rule1Obj[digit] = true;
      }
    }
    rule1Obj = {};
  }
  // 规则二:数字 1-9 在每一列只能出现一次。
  let rule2Obj = {};
  for (let n = 0; n < 9; n++) {
    for (let m = 0; m < 9; m++) {
      const digit = board[m][n] - 0;
      if (digit) {
        if (rule2Obj[digit]) {
          return false;
        }
        rule2Obj[digit] = true;
      }
    }
    rule2Obj = {};
  }
  // 规则三:数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
  let rule3Obj = {};
  for (let p = 0; p < 9; p += 3) {
    for (let q = 0; q < 9; q += 3) {
      for (let i = p; i < p + 3; i++) {
        for (let j = q; j < q + 3; j++) {
          const digit = board[i][j] - 0;
          if (digit) {
            if (rule3Obj[digit]) {
              return false;
            }
            rule3Obj[digit] = true;
          }
        }
      }
      rule3Obj = {};
    }
  }
  return true;
};

第二种就是在第一种的基础上进行优化,虽然结果却是不如第一次:

var isValidSudoku = function (board) {
  // 先将所有的值都设定好
  const typeObj = {
    row: { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {} },
    col: { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {} },
    ge: {
      0: { 0: {}, 1: {}, 2: {} },
      1: { 0: {}, 1: {}, 2: {} },
      2: { 0: {}, 1: {}, 2: {} },
    },
  };
  // 遍历一次,分别保存到对应的地方
  for (let i = 0; i < 9; i++) {
    for (let j = 0; j < 9; j++) {
      const digit = board[i][j] - 0;
      if (digit) {
        if (typeObj.row[i][digit]) {
          return false;
        } else if (typeObj.col[j][digit]) {
          return false;
        } else if (typeObj.ge[Math.floor(i / 3)][Math.floor(j / 3)][digit]) {
          return false;
        } else {
          typeObj.row[i][digit] = true;
          typeObj.col[j][digit] = true;
          typeObj.ge[Math.floor(i / 3)][Math.floor(j / 3)][digit] = true;
        }
      }
    }
  }
  return true;
};

官方的讲解: 有效的数独

我又想到一种方法,也就是在我的第二种的基础上,只保存所有的数字,如果遇到前面有的就根据规则来判断是否是三种中的一种。只不过在我实际的实现中发现使用哈希表存储是不好完成我这个想法,等我有新的存储方式我就完成这个想法。


来源:力扣(LeetCode)