Sudoku JavaScript数组

时间:2019-07-03 13:45:29

标签: javascript arrays sudoku

我接受了采访。我不得不现场编码。我无法解决问题,这里是问题

  • 您有两组嵌套数组,这些是规则
    • 每行必须包含1到9的数字,且不能重复。
    • 每列必须包含数字1到9,且无重复。
    • 每个3x3块必须包含1到9的数字,且不得重复。

我尝试了一下,但是我不知道如何添加遗漏的号码,其余的我也不知道


“使用严格”;

const invalidBoard = [
  [ 5, 3, 4,  6, 7, 9,  8, 1, 2 ],
  [ 6, 7, 2,  1, 9, 5,  3, 4, 7 ], 
  [ 6, 9, 8,  3, 4, 2,  7, 6, 5 ],

  [ 8, 5, 9,  7, 6, 1,  4, 2, 1 ],
  [ 4, 2, 6,  8, 5, 3,  7, 8, 1 ],
  [ 7, 1, 3,  9, 2, 4,  8, 5, 6 ],

  [ 9, 6, 1,  5, 3, 7,  2, 8, 4 ],
  [ 2, 8, 7,  4, 1, 9,  6, 3, 5 ],
  [ 3, 4, 5,  2, 8, 6,  1, 8, 8 ],
];

const validBoard = [
  [ 5, 3, 4,  6, 7, 8,  9, 1, 2 ],
  [ 6, 7, 2,  1, 9, 5,  3, 4, 8 ],
  [ 1, 9, 8,  3, 4, 2,  5, 6, 7 ],

  [ 8, 5, 9,  7, 6, 1,  4, 2, 3 ],
  [ 4, 2, 6,  8, 5, 3,  7, 9, 1 ],
  [ 7, 1, 3,  9, 2, 4,  8, 5, 6 ],

  [ 9, 6, 1,  5, 3, 7,  2, 8, 4 ],
  [ 2, 8, 7,  4, 1, 9,  6, 3, 5 ],
  [ 3, 4, 5,  2, 8, 6,  1, 7, 9 ],
];

console.log("Invalid board is invalid: " + !isValid(invalidBoard));
console.log("Valid board is valid: " + isValid(validBoard));

function isValid(board) {
 //this is what I wrote
 for(i=0; i<invalidBoard.length; i++){
let value = invalidBoard[i];
 const result= value.filter(item=>item<10)
 const sort= result.sort()

 const uniq=[... new Set(sort)]
 console.log(uniq)


 }
}

4 个答案:

答案 0 :(得分:2)

这是我的方法,首先检查所有行,然后将cols重新排列为行,并使用行验证器对其进行验证,并对块执行相同的操作。

.Query(q => q.Bool(b => b.Filter(f => f.DateRange(..))))

输出:

const invalidBoard = [
    [5, 3, 4, 6, 7, 9, 8, 1, 2],
    [6, 7, 2, 1, 9, 5, 3, 4, 7],
    [6, 9, 8, 3, 4, 2, 7, 6, 5],

    [8, 5, 9, 7, 6, 1, 4, 2, 1],
    [4, 2, 6, 8, 5, 3, 7, 8, 1],
    [7, 1, 3, 9, 2, 4, 8, 5, 6],

    [9, 6, 1, 5, 3, 7, 2, 8, 4],
    [2, 8, 7, 4, 1, 9, 6, 3, 5],
    [3, 4, 5, 2, 8, 6, 1, 8, 8]
];

const validBoard = [
    [5, 3, 4, 6, 7, 8, 9, 1, 2],
    [6, 7, 2, 1, 9, 5, 3, 4, 8],
    [1, 9, 8, 3, 4, 2, 5, 6, 7],

    [8, 5, 9, 7, 6, 1, 4, 2, 3],
    [4, 2, 6, 8, 5, 3, 7, 9, 1],
    [7, 1, 3, 9, 2, 4, 8, 5, 6],

    [9, 6, 1, 5, 3, 7, 2, 8, 4],
    [2, 8, 7, 4, 1, 9, 6, 3, 5],
    [3, 4, 5, 2, 8, 6, 1, 7, 9]
];

function validateRows(arr) {
    let isValid = true;
    arr.forEach(row => {
        let rowCopy = [...row];
        rowCopy.sort();
        rowCopy.forEach((number, index) => {
            if (number !== index + 1) {
                isValid = false;
            }
        });
    });

    return isValid;
}

function colsToRows(arr) {
    let ret = [];

    arr.forEach(row => {
        row.forEach((number, index) => {
            if (!Array.isArray(ret[index])) {
                ret[index] = [];
            }
            ret[index].push(number);
        });
    });

    return ret;
}

function blocksToRows(arr) {
    let blocks = [];
    let ret = [];

    for (let h = 0; h < 3; h++) {
        arr.forEach(row => {
            for (let i = 0; i < 3; i++) {
                blocks.push(row.shift());
            }
        });
    }

    for (let j = 0; j < 9; j++) {
        for (let k = 0; k < 9; k++) {
            if (!Array.isArray(ret[j])) {
                ret[j] = [];
            }
            ret[j].push(blocks.shift());
        }
    }

    return ret;
}


console.log(validateRows(invalidBoard));
console.log(validateRows(colsToRows(invalidBoard)));
console.log(validateRows(blocksToRows(invalidBoard)));

console.log(validateRows(validBoard));
console.log(validateRows(colsToRows(validBoard)));
console.log(validateRows(blocksToRows(validBoard)));

答案 1 :(得分:1)

这里是验证X和Y'轴的解决方案。 非常有趣的练习,检查平方组将花费更多时间,我将在稍后尝试。

const invalidBoard = [
  [ 5, 3, 4,  6, 7, 9,  8, 1, 2 ],
  [ 6, 7, 2,  1, 9, 5,  3, 4, 7 ], 
  [ 6, 9, 8,  3, 4, 2,  7, 6, 5 ],

  [ 8, 5, 9,  7, 6, 1,  4, 2, 1 ],
  [ 4, 2, 6,  8, 5, 3,  7, 8, 1 ],
  [ 7, 1, 3,  9, 2, 4,  8, 5, 6 ],

  [ 9, 6, 1,  5, 3, 7,  2, 8, 4 ],
  [ 2, 8, 7,  4, 1, 9,  6, 3, 5 ],
  [ 3, 4, 5,  2, 8, 6,  1, 8, 8 ],
];

const validBoard = [
  [ 5, 3, 4,  6, 7, 8,  9, 1, 2 ],
  [ 6, 7, 2,  1, 9, 5,  3, 4, 8 ],
  [ 1, 9, 8,  3, 4, 2,  5, 6, 7 ],

  [ 8, 5, 9,  7, 6, 1,  4, 2, 3 ],
  [ 4, 2, 6,  8, 5, 3,  7, 9, 1 ],
  [ 7, 1, 3,  9, 2, 4,  8, 5, 6 ],

  [ 9, 6, 1,  5, 3, 7,  2, 8, 4 ],
  [ 2, 8, 7,  4, 1, 9,  6, 3, 5 ],
  [ 3, 4, 5,  2, 8, 6,  1, 7, 9 ],
];

const validate_axis = data => {
  const _S = new Set(data)
  return [..._S].length === data.length
}

const validate = board => {
  const X_VALID = board.every(validate_axis)
  const Y_VALID = (
    board
    .map((_, i) => board.map(r => r[i]))
    .every(validate_axis)
  )
   
  return X_VALID && Y_VALID
}

const invalid = validate(invalidBoard)
const valid = validate(validBoard)

console.log(invalid)
console.log(valid)

答案 2 :(得分:0)

这里只有水平和垂直的解决方案:

$array = [9,1,9,1,3,9,1,2,9];

$arrayCounts = array_count_values($array);

usort($array, function ($a, $b) use ($arrayCounts) {
    $countA = $arrayCounts[$a] ?? 0;
    $countB = $arrayCounts[$b] ?? 0;
    if ($countA == $countB) {
       return $a == $b ? 0 : ($a < $b ? -1 : 1);
    }
    return ($countA > $countB) ? -1 : 1;
});

答案 3 :(得分:0)

让我们将其分解为最小的问题并积累起来


检查每个单元格的内容是否正确

首先,您要检查每个单元格的内容是否正确。为此,您必须验证每个单元格的值是19之间的数字。这很简单

function isCellContentValid(value) {
  return typeof value === "number" &&
    value >= 1 &&
    value <= 9;
}

console.log("1 => ",   isCellContentValid(1));
console.log("5 => ",   isCellContentValid(5));
console.log("9 => ",   isCellContentValid(9));
console.log("0 => ",   isCellContentValid(0));
console.log("42 => ",  isCellContentValid(42));
console.log("'a' => ", isCellContentValid('a'));

由于此代码非常简单,因此我们可以快速验证其正确性,并使用Array#every()可以检查整个行,并且可以确定该行是正确的,因为.every()将检查是否每个单元格都符合谓词:

function isCellContentValid(value) {
  return typeof value === "number" &&
    value >= 1 &&
    value <= 9;
}

function isRowContentValid(row) {
  return row.every(isCellContentValid);
}

console.log(isRowContentValid([1, 2, 3, 4, 5, 6, 7, 8, 9]))
console.log(isRowContentValid(['a', 2, 3, 4, 5, 6, 7, 8, 9]))

从那里,我们可以使用与上述相同的方法来检查整个电路板中是否包含有效内容-使用.every()来验证每一行:

function isBoardContentValid(board) {
  return board.every(isRowContentValid);
}

检查每一行是否包含唯一值

但是,我们还需要检查每个值集合是否包含唯一值。从行开始最简单,所以让我们开始吧。

有许多方法可以检查数组中的唯一性,但让我们采用一种易于阅读的方法。将数组的内容放入仅包含唯一值的Set中。如果集合和数组的大小相同,则意味着没有重复项。如果有,则该集合将不包含它们,并且其大小将有所不同:

function isArrayUnique(array) {
  const set = new Set(array);
  return set.size === array.length;
}

console.log(isArrayUnique([1, 2, 3]));
console.log(isArrayUnique([1, 2, 2]));

这很容易优化,但出于说明目的,它很简单。

一旦我们可以确保数组是唯一的...我们可以再次遍历每一行并使用.every()来验证每一行是否包含唯一值:

function areRowsUnique(board) {
  return board.every(isArrayUnique);
}

检查每一列是否包含唯一值

很酷,一次下来-我们检查了行。两个要走。接下来,我们再来看列。

列实际上只是,但垂直放置。如果可以用相同的方式处理它们,则可以重用相同的逻辑。这很棘手,但幸运的是,您可以通过执行matrix transposition来简化它,该操作实际上将使2D数组“旋转90度”,从而创建一个新的数组,其中的列现在是行:

function flipBoard(board) {
  //perform transposition
  return board[0].map((col, i) => board.map(row => row[i]));
}

//just to show off that it works
let exampleBoard = [
  ["a1", "b1", "c1"],
  ["a2", "b2", "c2"],
  ["a3", "b3", "c3"],
]

console.log(flipBoard(exampleBoard));

/* result:
["a1","a2","a3"]
["b1","b2","b3"]
["c1","c2","c3"]
*/

因此,检查所有列是否包含正确值的全部代码是旋转电路板并检查每一行(以前是一列):

function areColumnsUnique(board) {
  const flipped = flipBoard(board);
  return areRowsUnique(flipped);
}

检查每个正方形是否包含唯一值

总而言之,行和列都很简单。它们共享大多数代码,因此这是找到如何链接它们的问题。 3x3正方形会更难。如果我们可以将每个3x3正方形提取到9个元素的数组中,并收集每个元素,则可以再次重用先前的逻辑。

要做到这一点,从小节的角度考虑董事会是很有用的

║                       ║                       ║                       ║
║                       ║                       ║                       ║
║           A           ║           B           ║           C           ║
║                       ║                       ║                       ║
║                       ║                       ║                       ║
+=======+=======+=======+=======+=======+=======+=======+=======+=======+===========
║ (0,0) | (1,0) | (2,0) ║ (3,0) | (4,0) | (5,0) ║ (6,0) | (7,0) | (8,0) ║
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
║ (0,1) | (1,1) | (2,1) ║ (3,1) | (4,1) | (5,1) ║ (6,1) | (7,1) | (8,1) ║      1
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
║ (0,2) | (1,2) | (2,2) ║ (3,2) | (4,2) | (5,2) ║ (6,2) | (7,2) | (8,2) ║
+=======+=======+=======+=======+=======+=======+=======+=======+=======+===========
║ (0,3) | (1,3) | (2,3) ║ (3,3) | (4,3) | (5,3) ║ (6,3) | (7,3) | (8,3) ║
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
║ (0,4) | (1,4) | (2,4) ║ (3,4) | (4,4) | (5,4) ║ (6,4) | (7,4) | (8,4) ║      2
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
║ (0,5) | (1,5) | (2,5) ║ (3,5) | (4,5) | (5,5) ║ (6,5) | (7,5) | (8,5) ║
+=======+=======+=======+=======+=======+=======+=======+=======+=======+===========
║ (0,6) | (1,6) | (2,6) ║ (3,6) | (4,6) | (5,6) ║ (6,6) | (7,6) | (8,6) ║
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
║ (0,7) | (1,7) | (2,7) ║ (3,7) | (4,7) | (5,7) ║ (6,7) | (7,7) | (8,7) ║      3
+-------+-------+-------+-------+-------+-------+-------+-------+-------+
║ (0,8) | (1,8) | (2,8) ║ (3,8) | (4,8) | (5,8) ║ (6,8) | (7,8) | (8,8) ║
+=======+=======+=======+=======+=======+=======+=======+=======+=======+===========

这是一种形象的显示方式。每个单元格的内容指定其坐标,双线表示需要检查的每个3x3正方形。因此,我们需要将每个元素提取到一个数组中。为此,我们可以采用一些数学方法。但是首先,让我们从尝试做的事情开始-通过检查每个单元格的位置,我们看到坐标(0,0)的左上角属于A1。但是,(3,3)属于B2,而(7,6)在C3中。

由于我们希望将它们分别提取到一个数组中,所以让我们通过给它一个数字来重新标记每个正方形

+-------+-------+-------+
|       |       |       |
|   0   |   1   |   2   |
|       |       |       |
+-------+-------+-------+
|       |       |       |
|   3   |   4   |   5   |
|       |       |       |
+-------+-------+-------+
|       |       |       |
|   6   |   7   |   8   |
|       |       |       |
+-------+-------+-------+

比较两个都显示正方形的表示形式,我们可以看到每个坐标都落入了一个编号的正方形中,并且可以通过查看坐标来确定哪个。

  • (0,0)=> 0(A1)
  • (3,3)=> 4(B1)
  • (7,6)=> 8(C3)

因此,更笼统的是,我们可以导出公式以找到单元格所属的正方形的索引:(rowIndex / 3) * 3 + (columnIndex / 3)。我们需要在除法过程中舍入(本质上是执行整数除法)以获得整数。我们可以将以前的数字插入公式中,以验证其正确性:

  • (0,0)=>(0/3)* 3 +(0/3)= 0 * 3 + 0 = 0 + 0 = 0(A1)
  • (3,3)=>(3/3)* 3 +(3/3)= 1 * 3 +1 = 3 +1 = 4(B1)
  • (7,6)=>(7/3)* 3 +(6/3)= 2 * 3 + 2 = 6 + 2 = 8(C3)

说完所有这些,我们终于知道该怎么做-我们可以遍历整个板子,并根据每个单元格的坐标,将其放入与其正方形相对应的数组中。这将导致我们找到以下代码:

function extractSquares(board) {
  //nine arrays for each square
  const squares = [
    [], [], [], [], [], [], [], [], []
  ];

  board.forEach((row, rowIndex) => {
    row.forEach((cell, columnIndex) => {
      const squareIndex = (Math.floor(rowIndex / 3) * 3) + Math.floor(columnIndex / 3);

      squares[squareIndex].push(cell);
    })
  });

  return squares;
}

因此我们终于可以定义最后一个检查:

function areSquaresUnique(board) {
  const squares = extractSquares(board);
  return areRowsUnique(squares);
}

完整解决方案

将它们放在一起,我们得到以下信息:

function isValid(board){
  if (!isBoardContentValid(board)) {
    return false;
  }
  
  if (!areRowsUnique(board)) {
    return false;
  }
  
  if (!areColumnsUnique(board)) {
    return false;
  }
  
  if(!areSquaresUnique(board)) {
    return false;
  }
  
  return true;
}


function isCellContentValid(value) {
  return typeof value === "number" && value >= 1 && value <= 9;
}

function isBoardContentValid(board) {
  return board.every(isRowContentValid);
}

function isRowContentValid(row) {
  return row.every(isCellContentValid);
}

function isArrayUnique(array) {
  const set = new Set(array);
  return set.size === array.length;
}

function areRowsUnique(board) {
  return board.every(isArrayUnique);
}

function flipBoard(board) {
  return board[0].map((col, i) => board.map(row => row[i]))
}

function areColumnsUnique(board) {
  const flipped = flipBoard(board);
  return areRowsUnique(flipped);
}

function extractSquares(board) {
  //nine arrays for each square
  const squares = [
    [], [], [], [], [], [], [], [], []
  ];

  board.forEach((row, rowIndex) => {
    row.forEach((cell, columnIndex) => {
      const squareIndex = (Math.floor(rowIndex / 3) * 3) + Math.floor(columnIndex / 3);

      squares[squareIndex].push(cell);
    })
  });

  return squares;
}

function areSquaresUnique(board) {
  const squares = extractSquares(board);
  return areRowsUnique(squares);
}

///////////////////////////////////

const invalidBoard = [
  [ 5, 3, 4,  6, 7, 9,  8, 1, 2 ],
  [ 6, 7, 2,  1, 9, 5,  3, 4, 7 ], 
  [ 6, 9, 8,  3, 4, 2,  7, 6, 5 ],

  [ 8, 5, 9,  7, 6, 1,  4, 2, 1 ],
  [ 4, 2, 6,  8, 5, 3,  7, 8, 1 ],
  [ 7, 1, 3,  9, 2, 4,  8, 5, 6 ],

  [ 9, 6, 1,  5, 3, 7,  2, 8, 4 ],
  [ 2, 8, 7,  4, 1, 9,  6, 3, 5 ],
  [ 3, 4, 5,  2, 8, 6,  1, 8, 8 ],
];

const validBoard = [
  [ 5, 3, 4,  6, 7, 8,  9, 1, 2 ],
  [ 6, 7, 2,  1, 9, 5,  3, 4, 8 ],
  [ 1, 9, 8,  3, 4, 2,  5, 6, 7 ],

  [ 8, 5, 9,  7, 6, 1,  4, 2, 3 ],
  [ 4, 2, 6,  8, 5, 3,  7, 9, 1 ],
  [ 7, 1, 3,  9, 2, 4,  8, 5, 6 ],

  [ 9, 6, 1,  5, 3, 7,  2, 8, 4 ],
  [ 2, 8, 7,  4, 1, 9,  6, 3, 5 ],
  [ 3, 4, 5,  2, 8, 6,  1, 7, 9 ],
];


console.log(isValid(validBoard)); // => true

console.log(isValid(invalidBoard)); // => false