旋转编码的 3x3 matrix/list
Rotating an encoded 3x3 matrix/list
假设有一个编码的 3x3 平面:
1 2 3
4 5 6
7 8 9
顺时针旋转后变为:
7 4 1
8 5 2
9 6 3
要将前者转换为后者,一个明显的方法是做这样的事情:
switch (num) {
case 1: return 7; break;
case 2: return 4; break;
...
}
例如,[1, 5, 6, 9]
给出 [7, 5, 2, 3]
。
有没有不用硬编码就可以做到这一点的方法?
将值转换为新值的函数,将到达相同的位置,您可以使用下面定义的函数(在 JavaScript 中):
function rotated(num) {
num--; // convert to zero-based number
return 1 + (2 - num % 3) * 3 + Math.floor(num / 3);
}
// demo: print original and new value next to each other:
for (let num = 1; num <= 9; num++) {
console.log(num, rotated(num));
}
跟进
在评论中你问我是如何想出这个解决方案的。
有几种方法可以到达那里,但我认为这是这样的:
我想知道:如果我知道给定数字出现的行和列,那么从哪里获取新值的行和列是什么?
例如,3 出现在第 0 行和第 2 列(从零开始的索引编号)。我需要的值位于第 0 行和第 0 列。通过使用行和列,您会发现第 0 行中的所有条目都将从第 0 列获得它们的新值。同样,第 1 行中的那些将从第 1 列获得它们的新值。
与列号也有关系:第 0 列中的所有条目都从第 2 行获得它们的新值。那些第 1 列从第 1 行获得它们,而第 2 列中的那些从第 0 行获得它们。所以这里我们有相反的关系。
因此,给定一个数字,要采取的步骤是:
- 根据给定的数字得出它出现在哪一行和哪一列
- 从这些行和列索引派生出新值所在的其他行和列索引(遵循上述原则)
- 从其他行和列中得出哪个值位于那里 return 它。
到目前为止,我一直专注于步骤 2 的细节。第一步应该很容易。出现给定 num
的列索引是 (num-1) % 3
(模运算符)。行索引为(num-1)/3
(整数除法)。
第 3 步应该执行相反的操作:将行索引乘以 3,然后加上列索引。这给出了一个从零开始的值,因此应该向它添加 1。
所有这些导致以下代码:
function rotated(num) {
num--; // convert to zero-based number
// Step 1: derive row and column
let col = num % 3;
let row = Math.floor(num / 3);
// Step 2: derive other row and column
let valueCol = row;
let valueRow = 2 - col; // opposite direction
// Step 3: which value sits there?
let value = valueRow * 3 + valueCol + 1;
// Return that
return value;
}
// demo: print original and new value next to each other:
for (let num = 1; num <= 9; num++) {
console.log(num, rotated(num));
}
然后最后一步是减少该程序中使用的变量数量...这导致了上面的第一个代码段。
假设有一个编码的 3x3 平面:
1 2 3
4 5 6
7 8 9
顺时针旋转后变为:
7 4 1
8 5 2
9 6 3
要将前者转换为后者,一个明显的方法是做这样的事情:
switch (num) {
case 1: return 7; break;
case 2: return 4; break;
...
}
例如,[1, 5, 6, 9]
给出 [7, 5, 2, 3]
。
有没有不用硬编码就可以做到这一点的方法?
将值转换为新值的函数,将到达相同的位置,您可以使用下面定义的函数(在 JavaScript 中):
function rotated(num) {
num--; // convert to zero-based number
return 1 + (2 - num % 3) * 3 + Math.floor(num / 3);
}
// demo: print original and new value next to each other:
for (let num = 1; num <= 9; num++) {
console.log(num, rotated(num));
}
跟进
在评论中你问我是如何想出这个解决方案的。
有几种方法可以到达那里,但我认为这是这样的:
我想知道:如果我知道给定数字出现的行和列,那么从哪里获取新值的行和列是什么?
例如,3 出现在第 0 行和第 2 列(从零开始的索引编号)。我需要的值位于第 0 行和第 0 列。通过使用行和列,您会发现第 0 行中的所有条目都将从第 0 列获得它们的新值。同样,第 1 行中的那些将从第 1 列获得它们的新值。
与列号也有关系:第 0 列中的所有条目都从第 2 行获得它们的新值。那些第 1 列从第 1 行获得它们,而第 2 列中的那些从第 0 行获得它们。所以这里我们有相反的关系。
因此,给定一个数字,要采取的步骤是:
- 根据给定的数字得出它出现在哪一行和哪一列
- 从这些行和列索引派生出新值所在的其他行和列索引(遵循上述原则)
- 从其他行和列中得出哪个值位于那里 return 它。
到目前为止,我一直专注于步骤 2 的细节。第一步应该很容易。出现给定 num
的列索引是 (num-1) % 3
(模运算符)。行索引为(num-1)/3
(整数除法)。
第 3 步应该执行相反的操作:将行索引乘以 3,然后加上列索引。这给出了一个从零开始的值,因此应该向它添加 1。
所有这些导致以下代码:
function rotated(num) {
num--; // convert to zero-based number
// Step 1: derive row and column
let col = num % 3;
let row = Math.floor(num / 3);
// Step 2: derive other row and column
let valueCol = row;
let valueRow = 2 - col; // opposite direction
// Step 3: which value sits there?
let value = valueRow * 3 + valueCol + 1;
// Return that
return value;
}
// demo: print original and new value next to each other:
for (let num = 1; num <= 9; num++) {
console.log(num, rotated(num));
}
然后最后一步是减少该程序中使用的变量数量...这导致了上面的第一个代码段。