leetcode36题:有效的数独 解法

278 阅读3分钟

思路

根据数独的要求,可以已知几个条件。如果数独要有效必须满足三个条件

  • 在该行无重复数字
  • 在该列无重复数字
  • 以及在处于的小方块中无重复数字 所以可以从这三个条件入手
    1、遍历数独,对该数独上的每个字符进行判断
var isValidSudoku = function (board) {
  for (let i = 0; i < 9; i++) {
    for (let j = 0; j < 9; j++) {
        .....
    }
  }
};

2、如果是"." 则continue,判断下一位

var isValidSudoku = function (board) {
  for (let i = 0; i < 9; i++) {
    for (let j = 0; j < 9; j++) {
      if (board[i][j] == ".") {
        continue;
      } else {
            .....
      }
    }
  }
  return true;
};

3、否则就去判断该数在所在行、列、小方块上是否重复,这三个判断条件都是判断有无重复,差异在于判断所在行、所在列以及所在的小方块 ,所以可以把判断是否重复的这个抽出来写个函数,然后参数就是起始下标和结束下标

var isValid = function (board, start, end) {
  let map = new Map();   //创建一个map,key是每次遍历的数值,value是次数,起到一个存储的作用
  for (let i = start[0]; i <= end[0]; i++) {
    for (let j = start[1]; j <= end[1]; j++) {
      if (board[i][j] == ".") continue;  //如果是".",没必要判断,直接continue
      if (map.get(board[i][j])) {
          //如果在map中找到当前值的value,说明已经存储过了,重复了,直接return false
        return false;
      } else {
          //如果没有的话则进行存储
        map.set(board[i][j], 1);
      }
    }
  }
  return true;
};

4、判断所在行和所在列的下标都好表示

isValid(board, [i, 0], [i, 8])  //判断一行,所以只需遍历列
isValid(board, [0, j], [8, j])  //判断一列,所以只需遍历行

5、但是所在小方块的下标我们单独写个函数返回所在小方块的起始下标(左上)和结束下标(右下)
如果当前数值在第一个小方块内,他的起始下标就应该是[0,0],结束下标是[2,2]
如果在第二个小方块中,起始下标就应该是[0,3],结束下标是[2,5]
以此类推
可以得到规律,输入当前数值下标(i,j)
则他所在的小方块起始坐标[Math.floor(i / 3) * 3, Math.floor(j / 3) * 3]
结束下标是[Math.floor(i / 3) * 3+2, Math.floor(j / 3) * 3+2]

//把当前数值的行列传入
var getBoxRange = function (i, j) {
   //就可以得到起始下标和结束下标
  let start = [Math.floor(i / 3) * 3, Math.floor(j / 3) * 3];
   //结束下标不用再计算,只需在起始下标的行和列上再加2
  let end = [start[0] + 2, start[1] + 2];
  return [start, end];
};

6、只有个三个条件同时为true时,当前这个数才是有效的,只要有一个条件为false,则return false

var isValidSudoku = function (board) {
  for (let i = 0; i < 9; i++) {
    for (let j = 0; j < 9; j++) {
      if (board[i][j] == ".") {
        continue;
      } else {
        let box = getBoxRange(i, j);
        if (
          !isValid(board, [i, 0], [i, 8]) ||
          !isValid(board, [0, j], [8, j]) ||
          !isValid(board, box[0], box[1])
        ) {
          return false;
        }
      }
    }
  }
  return true;
};

完整代码

var isValid = function (board, start, end) {
  let map = new Map();
  for (let i = start[0]; i <= end[0]; i++) {
    for (let j = start[1]; j <= end[1]; j++) {
      if (board[i][j] == ".") continue;
      if (map.get(board[i][j])) {
        return false;
      } else {
        map.set(board[i][j], 1);
      }
    }
  }
  return true;
};

var getBoxRange = function (i, j) {
  let start = [Math.floor(i / 3) * 3, Math.floor(j / 3) * 3];
  let end = [start[0] + 2, start[1] + 2];
  return [start, end];
};

var isValidSudoku = function (board) {
  for (let i = 0; i < 9; i++) {
    for (let j = 0; j < 9; j++) {
      if (board[i][j] == ".") {
        continue;
      } else {
        let box = getBoxRange(i, j);
        if (
          !isValid(board, [i, 0], [i, 8]) ||
          !isValid(board, [0, j], [8, j]) ||
          !isValid(board, box[0], box[1])
        ) {
          return false;
        }
      }
    }
  }
  return true;
};

这个方法可以说是比较简单粗暴,理解起来比较容易
小白入门阶段