有效的数独

位运算

  1. 解题思路:

    • 基本知识:
      • 与运算(a&b):a,b 均为 1 时,返回 1,否则返回 0;
      • 异或运算(a^b):a,b 不同时为 0 或 1 时,返回 1,否则返回 0;
    • 本题可以使用一个 9 位二进制数判断数字是否被访问,第 k 位数为 1 代表已加入,为 0 代表未加入;
    • 更新方式(记九位数为 val,传入的数字为 n):
      • 判断是否加入:将九位数右移位 n 位,与 1 进行与运算; 结果为 0:未加入,将传入的数字加入九位数;结果为 1:已加入,返回 false;
      • 将传入的数字加入九位数:将 1 左移位 n 位,与 val 异或即可;
    • 例子:对于数字 1010010000,其第 4,7,9 位为 1,表示当前 4,7,9 已经访问过了;
      • 新来数字为 3:将 1010010000 右移 3 位得到 1010010,与 1 进行与运算,结果为 0,未访问过;将 1 左移位 3 位得到 1000,异或后得到 1010011000;
      • 新来数字为 4:将 1010010000 右移 4 位得到 101001,与 1 进行与运算,结果为 1,访问过;返回 false;
  2. 复杂度:

    • 时间复杂度:O(1);
    • 空间复杂度:O(1);
  3. 代码实现:

    var isValidSudoku = function (board) {
      // 保存 9行、9列、9块区域的 2进制值
      let row = new Array(9);
      let col = new Array(9);
      let area = new Array(9);
    
      for (let i = 0; i < 9; i++) {
        for (let j = 0; j < 9; j++) {
    
          let num = board[i][j];
          if (num == '.') continue;
          num = Number(num);
          let idx = Math.floor(i / 3) * 3 + Math.floor(j / 3);
    
          // 当前行,判断当前元素是否已经存在过
          // 当前列,判断当前元素是否已经存在过
          // 当前区域,判断当前元素是否已经存在过
          if ((((row[i] >> num) & 1) == 1) || (((col[j] >> num) & 1) == 1) || (((area[idx] >> num) & 1) == 1)) {
            return false;
          }
          console.log(Number(row[i]).toString(2));
          console.log(Number(1 << num).toString(2));
    
          // 不断更新 每一行、每一列、每一区域 的标记
          row[i] |= (1 << num);
          col[j] |= (1 << num);
          area[idx] |= (1 << num);
        }
      }
      return true;
    };
    

一次遍历

  1. 解题思路:

    • 可以使用哈希表记录每一行、每一列和每一个小九宫格中,每个数字出现的次数,只需要遍历数独一次,在遍历的过程中更新哈希表中的计数,并判断是否满足有效的数独的条件即可;
    • 利用一个 9*9 二维数组来存储行数据;
    • 利用一个 9*9 二维数组来存储列数据;
    • 利用一个 339 三维数组来存储区域Ï数据;
  2. 复杂度:

    • 时间复杂度:O(1),数独共有 81 个单元格,只需要对每个单元格遍历一次即可;
    • 空间复杂度:O(1),由于数独的大小固定,因此哈希表的空间也是固定的;
  3. 代码实现:

    var isValidSudoku = function (board) {
      // 9x9 矩阵:存储行数据
      const rows = new Array(9).fill(0).map(() => new Array(9).fill(0));
      // 9x9 矩阵:存储列数据
      const columns = new Array(9).fill(0).map(() => new Array(9).fill(0));
      // 3*3*9 矩阵(每行3个area,每列3个area,每个area有9个元素):存储区域元素
      const subboxes = new Array(3).fill(0).map(() => new Array(3).fill(0).map(() => new Array(9).fill(0)));
    
      for (let i = 0; i < 9; i++) {
        for (let j = 0; j < 9; j++) {
          const num = board[i][j];
    
          if (num !== '.') {
            const index = Number(num) - 1;
    
            // 第 i 行的 num 值 +!
            rows[i][index]++;
            // 第 i 列的 num 值 +!
            columns[j][index]++;
            // 第 x 区域的 num 值 +1
            subboxes[Math.floor(i / 3)][Math.floor(j / 3)][index]++;
    
            // 如果 第 i 行的 num 值的个数大于 1,则说明不满足要求,直接返回 false
            // 如果 第 i 列的 num 值的个数大于 1,则说明不满足要求,直接返回 false
            // 如果 第 x 区域的 num 值 的个数大于 1,则说明不满足要求,直接返回 false
            if (rows[i][index] > 1 ||
              columns[j][index] > 1 ||
              subboxes[Math.floor(i / 3)][Math.floor(j / 3)][index] > 1) {
              return false;
            }
          }
        }
      }
      // 全部迭代结束后,说明满足要求,返回 true
      return true;
    };
    
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 有效的数独
  2. 2. 位运算
  3. 3. 一次遍历