编写代码以确定一个数字是否可以被3整除。该函数的输入是单个位,0或1,如果到目前为止收到的数字是输出,则输出应为1可被3整除的数字的二进制表示,否则为零。
示例:
input "0": (0) output 1
inputs "1,0,0": (4) output 0
inputs "1,1,0,0": (6) output 1
这是基于面试问题。我要求绘制逻辑门,但由于这是stackoverflow,我会接受任何编码语言。硬件实现的奖励点(verilog等)。
Part a(easy):第一个输入是MSB。
B部分(稍微难一点):第一个输入是LSB。
C部分(困难):哪一个更快更小,(a)或(b)? (理论上不是Big-O意义上的,但实际上更快/更小。)现在采用更慢/更大的一个,并使其快/小与更快/更小的一样。
答案 0 :(得分:27)
通过交替地加上和减去其十进制数字,确定一个数是否是11的倍数有一个相当着名的技巧。如果你在最后得到的数字是11的倍数,那么你开始时的数字也是11的倍数:
47278 4 - 7 + 2 - 7 + 8 = 0, multiple of 11 (47278 = 11 * 4298) 52214 5 - 2 + 2 - 1 + 4 = 8, not multiple of 11 (52214 = 11 * 4746 + 8)
我们可以对二进制数应用相同的技巧。当且仅当其位的交替总和也是3的倍数时,二进制数是3的倍数:
4 = 100 1 - 0 + 0 = 1, not multiple of 3 6 = 110 1 - 1 + 0 = 0, multiple of 3 78 = 1001110 1 - 0 + 0 - 1 + 1 - 1 + 0 = 0, multiple of 3 109 = 1101101 1 - 1 + 0 - 1 + 1 - 0 + 1 = 1, not multiple of 3
无论是从MSB还是LSB开始都没有区别,因此以下Python函数在两种情况下都能正常工作。它需要一个迭代器一次返回一个位。 multiplier
在1和2之间交替而不是1和-1,以避免采用负数的模数。
def divisibleBy3(iterator):
multiplier = 1
accumulator = 0
for bit in iterator:
accumulator = (accumulator + bit * multiplier) % 3
multiplier = 3 - multiplier
return accumulator == 0
答案 1 :(得分:20)
这里......新的东西...如何检查任何长度(甚至数千个数字)的二进制数是否可以被3整除。
-->((0))<---1--->()<---0--->(1) ASCII representation of graph
从图片中可以看出。
您也可以使用它来生成可被3整除的数字。我不会想象将其转换为电路很难。
使用图表的示例...
11000000000001011111111111101可以被3整除(再次以双圈结束)
亲自试试。
在将二进制数转换为基数为10时,您也可以执行类似的操作来执行MOD 10。 (10个圆圈,每个圆圈加倍圈出,表示模数得到的值0到9)
编辑:这是针对从左到右运行的数字,虽然修改有限状态机以接受反向语言并不困难。
注意:在图形的ASCII表示中()表示单个圆圈,(())表示双圆圈。在有限状态机中,这些被称为状态,双圆是接受状态(意味着它最终可被3整除的状态)
答案 2 :(得分:11)
嘿
LSB的状态表:
S I S' O
0 0 0 1
0 1 1 0
1 0 2 0
1 1 0 1
2 0 1 0
2 1 2 0
说明:0可被3整除。 0 << 1 + 0 = 0
。如果S = (S << 1 + I) % 3
,请重复使用O = 1
和S == 0
。
MSB状态表:
S I S' O
0 0 0 1
0 1 2 0
1 0 1 0
1 1 0 1
2 0 2 0
2 1 1 0
说明:0可被3整除。 0 >> 1 + 0 = 0
。如果S = (S >> 1 + I) % 3
,请重复使用O = 1
和S == 0
。
S'
与上述不同,但O的作用相同,因为S'
对于相同的情况(00和11)为0。由于在两种情况下O都相同,O_LSB = O_MSB,所以要使MSB像LSB一样短,反之亦然,只需使用两者中最短的。
答案 3 :(得分:8)
这是一种手工操作的简单方法。 由于1 = 2 2 mod 3,对于每个正整数,我们得到1 = 2 2n mod 3。 此外,2 = 2 2n + 1 mod 3.因此,可以通过计算奇数位位置的1位来确定整数是否可被3整除,将该数乘以2,加1的数量偶数位的位将它们添加到结果中并检查结果是否可被3整除。
示例:57 10 = 111001 2 。 奇数位有2位,偶数位有2位。 2 * 2 + 2 = 6可被3整除。因此,57可被3整除。
这也是解决问题c)的想法。如果一个反转二进制整数的位顺序,则所有位保持在偶数/奇数位置或所有位都改变。因此,反转整数n的位的顺序结果是一个整数,当且仅当n可被3整除时,该整数可以被3整除。因此问题a)的任何解决方案都可以在不改变问题b)的情况下工作,反之亦然。嗯,也许这有助于弄清楚哪种方法更快......
答案 4 :(得分:7)
您需要使用算术模3进行所有计算。这就是
的方式MSB:
number=0
while(!eof)
n=input()
number=(number *2 + n) mod 3
if(number == 0)
print divisible
LSB:
number = 0;
multiplier = 1;
while(!eof)
n=input()
number = (number + multiplier * n) mod 3
multiplier = (multiplier * 2) mod 3
if(number == 0)
print divisible
这是一般的想法......
现在,您的目的是了解为什么这是正确的。
是的,自己做作业;)
答案 5 :(得分:4)
这个想法是这个数字可以任意增长,这意味着你不能在这里使用mod 3
,因为你的数字将超出你的整数类的容量。
想法是注意数字会发生什么。如果你在右边添加位,你实际做的是向左移一位并添加新位。
Shift-left与乘以2相同,添加新位是添加0或1.假设我们从0开始,我们可以根据最后一个数字的模3进行递归。
last | input || next | example
------------------------------------
0 | 0 || 0 | 0 * 2 + 0 = 0
0 | 1 || 1 | 0 * 2 + 1 = 1
1 | 0 || 2 | 1 * 2 + 0 = 2
1 | 1 || 0 | 1 * 2 + 1 = 0 (= 3 mod 3)
2 | 0 || 1 | 2 * 2 + 0 = 1 (= 4 mod 3)
2 | 1 || 2 | 2 * 2 + 1 = 2 (= 5 mod 3)
现在让我们看看当你向左边添加一些内容时会发生什么。首先,请注意:
2 2n mod 3 = 1
和
2 2n + 1 mod 3 = 2
所以现在我们必须根据当前迭代是奇数还是偶数来为mod添加1或2。
last | n is even? | input || next | example
-------------------------------------------
d/c | don't care | 0 || last | last + 0*2^n = last
0 | yes | 1 || 0 | 0 + 1*2^n = 1 (= 2^n mod 3)
0 | no | 1 || 0 | 0 + 1*2^n = 2 (= 2^n mod 3)
1 | yes | 1 || 0 | 1 + 1*2^n = 2
1 | no | 1 || 0 | 1 + 1*2^n = 0 (= 3 mod 3)
1 | yes | 1 || 0 | 2 + 1*2^n = 0
1 | no | 1 || 0 | 2 + 1*2^n = 1
答案 6 :(得分:0)
实际上LSB方法实际上会使这更容易。在C:
MSB方法:
/*
Returns 1 if divisble by 3, otherwise 0
Note: It is assumed 'input' format is valid
*/
int is_divisible_by_3_msb(char *input) {
unsigned value = 0;
char *p = input;
if (*p == '1') {
value &= 1;
}
p++;
while (*p) {
if (*p != ',') {
value <<= 1;
if (*p == '1') {
ret &= 1;
}
}
p++;
}
return (value % 3 == 0) ? 1 : 0;
}
LSB方法:
/*
Returns 1 if divisble by 3, otherwise 0
Note: It is assumed 'input' format is valid
*/
int is_divisible_by_3_lsb(char *input) {
unsigned value = 0;
unsigned mask = 1;
char *p = input;
while (*p) {
if (*p != ',') {
if (*p == '1') {
value &= mask;
}
mask <<= 1;
}
p++;
}
return (value % 3 == 0) ? 1 : 0;
}
我个人很难相信其中一个会与另一个明显不同。
答案 7 :(得分:0)
input "0": (0) output 1
inputs "1,0,0": (4) output 0
inputs "1,1,0,0": (6) output 1
这个最后的输入不应该是12
,还是我误解了这个问题?
答案 8 :(得分:-1)
我认为Nathan Fellman在a和b部分的正确轨道上(除了b需要一个额外的状态:你需要跟踪你的数字位置是奇数还是偶数)。
我认为 C部分的技巧是在每一步都否定last
值。即0变为0,1变为2,2变为1。
答案 9 :(得分:-1)
如果数字的总和可以被3整除,则数字可以被3整除。
所以你可以添加数字并得到总和: