javascript - 熄灯算法 - 找到打开所有开关的最小开关数量
问题描述
该组开关位于水平行中。最右边的开关可以随时打开或关闭。只有当右侧的开关打开且右侧的所有其他开关都关闭时,才能切换任何其他开关。所有开关最初都是关闭的。创建一个函数,该函数接受 n 个开关并返回打开所有开关所需的最小开关次数。需要输出切换开关的每一步。
Example:
n = 3;
[0; 0; 0] --> [0; 0; 1] --> [0; 1; 1] --> [0; 1; 0] --> [1; 1; 0] --> [1; 1; 1];
count = 5.
我的想法是测试我们想要启用的下一个开关。然后检查它右侧的每个开关并检查所需的状态。你能建议什么解决方案?
解决方案
这实际上产生了一个格雷码序列。
虽然您当然可以以一种非常幼稚的方式实现这一点,但我们也可以使用以下观察:当我们从右到左对数组中的索引进行编号时,从最右边的条目的 0 开始,然后是数字应该切换的索引遵循以下顺序:
0 1 0 2 0 1 0 3 0 1 0 2 0...
当我们从 1 开始对输出进行编号时,上述索引对应于该编号中最右边 1 位的索引。该表应说明这一点:
输出编号 | 二进制 | 最右边 1 的索引 | 格雷码 |
---|---|---|---|
1 | 00001 | 0 | 00001 |
2 | 00010 | 1 | 00011 |
3 | 00011 | 0 | 00010 |
4 | 00100 | 2 | 00110 |
5 | 00101 | 0 | 00111 |
6 | 00110 | 1 | 00101 |
7 | 00111 | 0 | 00100 |
8 | 01000 | 3 | 01100 |
9 | 01001 | 0 | 01101 |
10 | 01010 | 1 | 01111 |
... |
如果输入不超过 31 个(灯泡),我们可以使用 32 位操作来导出最右边 1 位的索引。例如i & ~(i - 1)
,返回设置的最低有效位i
- 作为 2 的幂。要将 2 的幂转换为位索引,我们可以使用鲜为人知的Math.clz32
函数。
我们可以跟踪有多少灯泡打开并在所有灯泡都打开时停止循环(实际上在每次迭代中从零开始计数灯泡):
function steps(bulbCount) {
let i, onCount;
const bulbs = Array(bulbCount).fill(0);
console.log(...bulbs);
for (i = 1, onCount = 0; onCount < bulbCount; i++) {
let index = bulbCount + Math.clz32(i & ~(i - 1)) - 32;
bulbs[index] ^= 1; // Toggle
onCount += bulbs[index] || -1; // Either increment or decrement
console.log(...bulbs);
}
return i - 1; // Number of switch actions
}
console.log("Number of switch operations: ", steps(4));
对于更多数量的灯泡,您需要用更“手动”的相同原理实现来替换位运算符,但是当您必须等待生成超过 2 31个输出时,几乎没有任何实际用途......
选择
我们还可以使用来自Wikipedia的以下观察:
第th个格雷码是通过计算⊕⌊/2⌋</p>得到的
虽然使用 32 位运算符进行此计算很简单,但需要在每次迭代中从一个数字构建数组:
function steps(bulbCount) {
let i, onCount,
bits = 0,
end = (1 << bulbCount) - 1;
const bulbs = Array(bulbCount).fill(0);
console.log(...bulbs);
for (i = 1; bits < end; i++) {
bits = i ^ (i >> 1);
console.log(...Array.from(bits.toString(2).padStart(bulbCount, "0"), Number));
}
return i - 1; // Number of switch actions
}
console.log("Number of switch operations: ", steps(4));
推荐阅读
- javascript - Laravel 5:附加输入文本取决于所选选项 vue js
- python - 使用python将数据文件拆分为单独的文件
- amazon-web-services - Fargate 任务(容器)是否可以检索其元数据,例如服务名称?
- python - 绘制两个具有不同索引类型的 Panda 数据框
- list - 我如何对HashMap进行排序
按他们在 Kotlin 中的值排序? - python - Spacy - 将相似性函数应用于熊猫行中的文档
- javascript - 滚动时的jQuery不透明度被切断
- python - catalina 10.51.1 python3 w brew 或 xcode-select
- android - 如何在android datepicker中获取月份的第一个和最后一个日期
- django - 将views.py中的视图合并为一个视图?