[英]Bitwise OR ( | ) and Bitwise Operator ( ~ ) - Javascript
挑战:给定整数N
和K
(其中2 <= K <= N
),找到A & B
的最大值(即 A 按位与 B)使得0 <= A < B <= N
和(A & B) < K
我已经制作了我的代码,它在可见情况下运行完美,但在隐藏情况下却失败了。
我的代码:
function bitwiseAnd(N, K) {
// Write your code here
let arr = []
N = parseInt(N,10)
K = parseInt(K,10)
for(let a=1; a<N; a++){
for(let b=a+1; b<=N ; b++){
if(K>=0 && parseInt(a&b,10) < K && parseInt(a&b,10)>=0) arr.push(parseInt(a&b,10))
}
}
return Math.max(...arr)
}
我搜索了一个解决方案,我找到了这个。
解决方案:
function bitwiseAnd(N, K) {
// Write your code here
var n = parseInt(N);
var k = parseInt(K);
var a = k - 1;
var b = (~a) & -(~a);
if ( (a | b) > n )
return(a - 1);
else
return(a);
}
但是解决方案的代码在所有隐藏测试中都运行良好,我不明白它是如何工作的,因为我不熟悉按位运算符。
有没有机会得到这个运营商的解释以及如何使用?
提前致谢。
这是您的代码的一个变体:
function bitwiseAnd(N, K) { let r = 0; for(let a=1; a<N; a++) { for(let b=a+1; b<=N; b++) { if((a&b) < K) r = Math.max(r, a&b) } } return r } console.log(bitwiseAnd(5,2)) // 1 console.log(bitwiseAnd(8,5)) // 4 console.log(bitwiseAnd(2,2)) // 0
我删除了不必要的 parseInts 和结果检查。 但是,您的代码唯一真正错误的是行Math.max(...arr)
。
该行的问题在于它没有将对arr
的引用传递给 Math.max 方法。 相反,它实际上将arr
的所有成员包括为 arguments,这将出现在 Javascript 调用堆栈中。 通常,这会很好。 但是,如果数组中有数十万个值,则会超出最大调用堆栈大小,您的代码将无法执行。 这就是为什么一个隐藏的测试用例,它一定会导致大量的数组成员,导致 hackerrank 拒绝你的解决方案。
您还发布了一个非常有趣的解决方案,它根本不使用循环。
我已经稍微清理了一下,并将其包含在下面:
function bitwiseAnd(n, k) { let a = k-1 return (a | ~a & a+1) <= n? a: a-1 } console.log(bitwiseAnd(5,2)) // 1 console.log(bitwiseAnd(8,5)) // 4 console.log(bitwiseAnd(2,2)) // 0
请注意,原始代码说的& -(~a)
而不是& a+1
。 取反数的补码方法是翻转所有位并将结果加一。 由于按位非~
也意味着翻转所有位,原代码翻转所有位,再次翻转所有位,然后加一。 因此,这是简单地执行a+1
的混淆。
以下是对该代码背后的思想的解释:
由于A & B
的结果必须小于K
,因此结果的最大数量将为K-1
。
当我们执行按位A & B
时,结果只能关闭某些位,而不能打开任何位。 由于A
必须小于B
,并且由于我们只能关闭A
的位,因此A & B
的结果不能超过A
的值。
结合以上两个结论,我们可以得出结论:
B
将保留A
A
选择不能超过K-1
。 因此,让我们看看是否可以将A
设置为K-1
并找到B
的值,该值将保留A
中的所有位。
将保留A
的所有位的大于A
的第一个值将是设置当前未设置的最低有效位的结果。
例如,如果A = 101
,则在执行A & B
之后将保留A
所有位的B
的下一个值是111
。
为了定位最低有效未设置位的 position,我们可以执行~A & A+1
。 对于A
为101
的示例, ~A & A+1
为010
。 本质上, ~A & A+1
,无论A
的值是多少,都将始终返回仅包含一个设置位的二进制序列。
这样做的原因是~A
充当掩码,只允许~A & A+1
的结果包含A
中未设置的位。 当我们执行A+1
时,将在A
中第一次设置的第一个位将是最低有效未设置位,并且不会第一次设置其他位。
例如:如果A
= 101
, ~A = 010
, A+1 = 110
,所以~A & A+1 = 010 & 110 = 010
。 答案中的1
是 A 中最低有效未设置位的A
。
如果我们进行按位或,我们可以使用这个结果来计算B
的第一个较高值,这将保留A
所有位。 因此B = A | ~A & A+1
B = A | ~A & A+1
。 因此,我们可以在上面的可运行代码片段中看到,如果我们发现(a | ~a & a+1) <= n
,我们知道a = k-1
的值将起作用,我们可以将其作为回答。
但是,如果B
的值超过N
怎么办? 我们需要找到下一个最佳答案。
由于我们尝试A = K-1
,并且由于问题表明K <= N
,这意味着A
一定是奇数(即设置了最低有效位)。 这是因为如果A
是偶数,我们会尝试值B = A + 1
,并且B
不能超过N
因为K <= N
和A = K-1
。
因此,由于我们之前尝试A = K-1
时尝试失败,我们知道我们不能比A
高 go 来找到在A = K-1
时有效的B
值。
但是,如果我们设置A = K-2
,并且因为我们知道K-1
是奇数,这意味着K-2
是偶数。 这意味着我们可以有A = K-2
和B = K-1
,以及A & B = K-2
。 因此 function 的结果是K-2
。
因此,代码也许可以更清楚地写成:
function bitwiseAnd(n, k) { let a = k-1 return (a | ~a & a+1) <= n? k-1: k-2 } console.log(bitwiseAnd(5,2)) // 1 console.log(bitwiseAnd(8,5)) // 4 console.log(bitwiseAnd(2,2)) // 0
底线是我们不需要任何循环,因为总有一个答案,其中A = K-1
和B
比A
高一个以上,或者A = K-2
和B = K-1
。
但是,我们可以做出改进...
到目前为止,我们已经解释了您发布的解决方案背后的想法。 然而,该解决方案比它需要的更复杂。
如果我们想获取A
并设置最低有效未设置位,我们可以简单地执行A | A+1
A | A+1
。
这意味着更简单的解决方案是:
function bitwiseAnd(n, k) { let a = k-1 return (a | a+1) <= n? k-1: k-2 } console.log(bitwiseAnd(5,2)) // 1 console.log(bitwiseAnd(8,5)) // 4 console.log(bitwiseAnd(2,2)) // 0
而且,如果我们真的想对解决方案进行编码,我们可以替换变量a
,并利用 Javascript 将 true/false 强制转换为 1/0 并执行以下操作:
function bitwiseAnd(n, k) { return --k-((k++|k)>n) } console.log(bitwiseAnd(5,2)) // 1 console.log(bitwiseAnd(8,5)) // 4 console.log(bitwiseAnd(2,2)) // 0
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.