试图找到满足n + x = n ^ x的x的数量会因超时而失败

时间:2017-01-04 14:48:26

标签: java algorithm bit-manipulation java-stream xor

我正在尝试使用Java 8的新功能(例如Stream s)在Hacker Rank site位操作部分解决以下问题。

问题描述:

  

给定一个整数n,找到每个x,使得:

     
      
  • 0< = x< = n
  •   
  • n + x = n ^ x
  •   
     

其中^表示按位XOR运算符。然后打印一个整数,表示满足上述条件的x的总数。

     

约束

     
      
  • 0< = n< = 10 15
  •   
     

示例输入: 5

     

示例输出: 2

     

解释

     

对于 n = 5 x 0 2 满足条件:

     
      
  • 5 + 0 = 5 ^ 0 = 5
  •   
  • 5 + 2 = 5 ^ 2 = 7
  •   
     

因此,我们打印 2 作为我们的答案。

     

示例输入: 10

     

示例输出: 4

     

说明:   对于 n = 10 x 0 1 4 ,以及 5 满足条件:

     
      
  • 10 + 0 = 10 ^ 0 = 10
  •   
  • 10 + 1 = 10 ^ 1 = 11
  •   
  • 10 + 4 = 10 ^ 4 = 14
  •   
  • 10 + 5 = 10 ^ 5 = 15
  •   
     

因此,我们打印 4 作为我们的答案。

我的代码如下:

public class SumVsXor 
{
    public static void main(String[] args) 
    {
        Scanner in = new Scanner(System.in);
        long n = in.nextLong();
        long count = LongStream.rangeClosed(0, n)
                               .filter(k -> k + n == (k ^ n))
                               .count();
        System.out.println(count);  
    }
}

问题是此代码未通过所有测试用例。

它适用于n的小值,但对于1000000000000000这样的大值,它会因超时而失败。

我想知道LongStream是否无法使用那么多元素来处理Stream

4 个答案:

答案 0 :(得分:22)

您的代码存在问题,效率非常低。对于n==1000000000000000的情况,您的Stream管道正在执行1,000,000,000,000,000添加和XOR操作,这需要很长时间。测试0到n之间的每个数字,即使使用for循环而不是n + x == n ^ xStream将花费很长时间。

您应该尝试找出一种更好的方法来计算所需的x总数,而不是检查0和n之间的所有数字。这个问题出现在“位操作”部分下的事实应该给你一个提示 查看满足n + x == n ^ x的数字位数。

让我们考虑n==1000000000000000的情况。该大数字的二进制表示是

0000000000000011100011010111111010100100110001101000000000000000
              ===   == = ====== = =  =  ==   == =
                 ---  - -      - - -- --  ---  - ---------------
~~~~~~~~~~~~~~              

为了使n + x等于n ^ xx必须在与0位对应的所有位中具有1值{1}}(上面标有n),以及与=的{​​{1}}位对应的位中的01值(标有上面0)。这不包括前导n s(上面标有-),因为x必须是< = 0,因此{{1}中的任何前导~ }} n中的0值也必须为n

这意味着0为{2}的x的总数为xn + x == n ^ x的数量,不包括前导0

对于n,有0n = 1000000000000000位,因此符合要求的30总数为2 30

以下是计算0总数的一种方法:

x

答案 1 :(得分:2)

我得出了相同的结果,但是通过不同的解释,我想我可以在这里发布。

Eran的回答得出了我所做的相同结论:修改初始数字的二进制表示中的零 - 这非常简单。

我们假设我们的数字是

  

101010100

所以它有5个零。

您需要以下所有可能的组合:

  • 一个零
  • 两个零
  • 三个零
  • 四个零
  • 五个零

实际上是:

 comb(1,5) + comb(2,5) + comb(3,5) + comb(4,5) + comb (5,5)

这是一个众所周知的公式,等于:

  

pow(2,n)//其中n在我们的例子中是5

从那里解决方案很明显......

答案 2 :(得分:1)

public static void main (String[] args) {
    Scanner in = new Scanner (System.in);
    long n = in.nextLong();
    long count = 1L << (64-Long.bitCount(n)-Long.numberOfLeadingZeros(n));
    System.out.println(count);
}

答案 3 :(得分:1)

如果您对XOR知之甚少,这是一个简单的问题。我不太了解java。但我可以在python中解释。

1.首先将数字转换为二进制数。 2.计算该二进制数中的零个数。 3.print 2 ^(零的数量)就是这样。

这是我的python代码。

n = int(input())
sum = 0
if n!=0:
    n=str(bin(n))
    for i in range(len(n)):
            if n[i]=='0':
           sum = sum + 1
    print(2**(sum-1))
else: print(1)

将和减1的原因是,在python中它将数字转换为二进制格式。例如:0b'10101。