为什么[]和新Array之间存在差异



我正在研究流行的NQueen问题。下面的代码简单地返回了可能的方法的数量。它根据板矩阵的传递方式给出不同的输出。

// just a helper function
const isSafe = (board, row, col) => {
for (let i = row; i >= 0; i--) {
if (board[i][col]) return false;
}
for (let i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (board[i][j]) return false;
}
for (let i = row, j = col; i >= 0 && j < board.length; i--, j++) {
if (board[i][j]) return false;
}
for (let i = row; i >= 0; i--) {
if (board[i][col]) return false;
}
return true;
};
const getWays = (board, row) => {
if (row == board.length) {
return 1;
}
let count = 0;
for (let col = 0; col < board.length; col++) {
if (isSafe(board, row, col)) {
board[row][col] = true;
count += getWays(board, row + 1);
board[row][col] = false;
}
}
return count;
};

如果我像下面这样调用getWays,则输出为2,这是正确的

const n = 4;
let board = new Array(n).fill(new Array(n).fill(false));
for (let i = 0; i < n; i++) {
board[i] = new Array(n).fill(false);
}
console.log(getWays(board, 0));

但如果我像下面这样调用getWays,答案是0,这是不正确的

const n = 4;
let board = new Array(n).fill(new Array(n).fill(false));
console.log(getWays(board, 0));

我不明白这两种创建矩阵的方法是如何导致不同的输出的,即使它们生成了相同的矩阵。有人能用一点解释和链接到任何文档(如果适用/可能)来指出我遗漏了什么吗?

让我们解构这句话:
let board = new Array(n).fill(new Array(n).fill(false));

您正在创建一个名为board的新变量,并为其分配一些内容

你给它分配了什么
new Array(4),您最初也用";什么";。

那是什么;什么">
它是对new Array(4)引用,您可以用false填充该引用
这是一个false填充的新阵列

因此是一个数组,有四个引用到相同数组
如果在一行中更改该数组,则所有其他行也会更改。你可以通过一个小的测试程序看到这一点。

const n = 4;
let board = new Array(n).fill(new Array(n).fill(false));
console.log(board);
board[0][2] = 'Q';
console.log(board[2][2]);

在Stackoverflow中运行此代码段会产生输出:

[
[
/**id:2**/
false,
false,
false,
false
],
/**ref:2**/,
/**ref:2**/,
/**ref:2**/
]

阵列的第一个元素被赋予2id,而的其他三个元素对2有一个引用,告诉你它们是相同的阵列所以更改一个会更改所有行——比如board[0][2]="Q"也会使console.log(board[2][2])显示为"0";Q";

这在浏览器控制台中看起来有所不同,它可能会将第一个console.log(board)显示为:

console.log(board)
(4) [Array(4), Array(4), Array(4), Array(4)]
0: (4) [false, false, false, false]
1: (4) [false, false, false, false]
2: (4) [false, false, false, false]
3: (4) [false, false, false, false]
length: 4

然后,如果您在分配给一个单元格后再次将写入控制台输出,您将看到效果:

board[0][2]='Q';
console.log(board)
(4) [Array(4), Array(4), Array(4), Array(4)]
0: (4) [false, false, "Q", false]
1: (4) [false, false, "Q", false]
2: (4) [false, false, "Q", false]
3: (4) [false, false, "Q", false]
length: 4

现在,在工作的第一种情况下,您可以使用循环遵循初始语句

for (let i = 0; i < n; i++) {
board[i] = new Array(n).fill(false);
}

这样做是从board[0]到board[3]丢弃的原始内容,丢弃对一个数组的四个引用,而是分配四个新创建的数组。它相当于这个系列,不使用循环:

const n = 4;
let board = new Array(n);
let r = new Array(n).fill(false);
board[0] = r;
board[1] = r;
board[2] = r;
board[3] = r;
// A little clearer here that board[0] through board[3] all contain references to 'r'
console.log(board);
// Now replace those references to 'r' with new Arrays...
board[0] = new Array(n).fill(false);
board[1] = new Array(n).fill(false);
board[2] = new Array(n).fill(false);
board[3] = new Array(n).fill(false);
console.log(board);

相关内容

最新更新