如果给出两个整数A和B,其中0 <= A <= B <= 2 ^ 32。找到范围(A,B)中的整数的按位AND。例如,A = 12且B = 15,
12&amp; 13&amp; 14&amp; 15 = 12
我的TA没有做太多解释如何解决问题,而是在办公时间结束时给每个人留下了解决方案,现在,我无法解决问题,但我也不明白解决方案。在下面的代码中,我注意到我理解并且不理解的行。
我尝试过用小As和B做自己的例子的笔和纸方法,而我可以看到代码工作,我无法掌握代码工作原理背后的理论。
private void run() {
Scanner in = new Scanner(System.in);
long a = in.nextLong();
long b = in.nextLong();
long diff = Math.max(((long) (Math.log(b - a) / Math.log(2)) - 1), 0);
//what does diff represent?
long shiftA = a >> diff; //right shift by diff okay
long shiftB = b >> diff; // " "
long result = shiftA;
for (long j = shiftA; j <= shiftB; j++) {
result = result & j; //don't understand the loop
}
result = result << diff; //left shift, but why?
System.out.println(result);
}
}
答案 0 :(得分:3)
差异代表什么?
diff
使用change of base formula for logarithms来计算差异b-a
的表示位数。如果差异需要K
位来表示,那么K-1
范围中某个数字的结果的最后[a..b]
位将全部设置为零,这意味着您可以清除他们出了结果。因此,最后左移diff
:它会将diff
0转换为结果。
我不理解循环
循环通过位表示减少2 diff 次,即仅使用a
和b
的高位。由于低diff
位无论如何都将设置为零,因此此解决方案计数为2 diff 而不是按1
计数,从而减少了到达结果所需的时间。
考虑a=23
和b=39
的示例。 diff
等于3
。以下是表示,用逗号分隔最后3位:
d b
-- -------
23 010,111
24 011,000
25 011,001
26 011,010
27 011,011
28 011,100
29 011,101
30 011,110
31 011,111
32 100,000 <<-- The last diff bits will be set to zero somewhere in the range
33 100,001
34 100,010
35 100,011
36 100,100
37 100,101
38 100,110
39 100,111
由于最后三位保证全部为零,因此循环可以计数8,而不是按1计数。这将执行速度降低了八倍。通过将数字首先向右移动diff
,然后按1计数,然后向左移动diff
来完成8的计数。
答案 1 :(得分:2)
diff
部分只是一个优化,使得代码更复杂和棘手(在某些边缘情况下可能是错误的)以节省一些运行时间。 (一般来说,只有当性能很重要并且只有良好的测试时,这才是一个好主意。在这里,我们可以轻松地花更多时间来理解优化并使其正确,而不是运行未经优化的程序几次。)
让我们首先讨论基本循环,设置diff = 0
。所以a >> diff
== a
和result << diff
== result
,所以我们可以忽略所有这些。
主循环直接实现解决方案:
long result = a;
for (long j = a; j <= b; j++) {
result = result & j;
}
即,bitand(&
)每个值一起来自范围[a ... b]。给定a = 12且b = 15,即12 & 13 & 14 & 15
。 (实际上,如果你仔细地手工模拟它,你会注意到它会计算12 & 12 & 13 & 14 & 15
,这会得到相同的结果。)这是理解,基本循环和按位数学的重要部分。
diff
部分通过删除低阶位使代码更快。例如。如果某些输入值计算diff == 4
,则a >> 4
会移出a
的低4位,基本上为a / 16
,因为2 4 == 16然后循环将多次运行1/16。然后,代码将结果重新移位result << 4
,移位为0位,基本上为a * 16
。
在diff
的值上,请注意Math.log(b - a) / Math.log(2)
== log 2 (b - a),这是b - a
中的位数。它正在努力计算最终为零的低阶位的数量,以便它可以将它们移出,循环次数减少,然后在末尾以零移位。
答案 2 :(得分:0)
更简单,也更容易理解:
long result = firstValue;
for ( long i=result+1; i <= lastValue; i++ ) {
result &= i;
}