繁体   English   中英

按位或 (|) 和按位运算符 (~) - Javascript

[英]Bitwise OR ( | ) and Bitwise Operator ( ~ ) - Javascript

挑战:给定整数NK (其中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的混淆。

以下是对该代码背后的思想的解释:

  1. 由于A & B的结果必须小于K ,因此结果的最大数量将为K-1

  2. 当我们执行按位A & B时,结果只能关闭某些位,而不能打开任何位。 由于A必须小于B ,并且由于我们只能关闭A的位,因此A & B的结果不能超过A的值。

结合以上两个结论,我们可以得出结论:

  1. 如果我们选择B将保留A A选择不能超过K-1

因此,让我们看看是否可以将A设置为K-1并找到B的值,该值将保留A中的所有位。

将保留A的所有位的大于A的第一个值将是设置当前未设置的最低有效位的结果。

例如,如果A = 101 ,则在执行A & B之后将保留A所有位的B的下一个值是111

为了定位最低有效未设置位的 position,我们可以执行~A & A+1 对于A101的示例, ~A & A+1010 本质上, ~A & A+1 ,无论A的值是多少,都将始终返回仅包含一个设置位的二进制序列。

这样做的原因是~A充当掩码,只允许~A & A+1的结果包含A中未设置的位。 当我们执行A+1时,将在A中第一次设置的第一个位将是最低有效未设置位,并且不会第一次设置其他位。

例如:如果A = 101~A = 010A+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 <= NA = K-1

因此,由于我们之前尝试A = K-1时尝试失败,我们知道我们不能比A高 go 来找到在A = K-1时有效的B值。

但是,如果我们设置A = K-2 ,并且因为我们知道K-1是奇数,这意味着K-2是偶数。 这意味着我们可以有A = K-2B = 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-1BA高一个以上,或者A = K-2B = 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM