【问题标题】:Finding all pairs of numbers in an array whose bitwise and is 0查找数组中按位和为0的所有数字对
【发布时间】:2015-09-05 17:33:11
【问题描述】:

我最近遇到一个问题,它是关于计算数组中按位 & 为 0 的所有数字对。所需的复杂度为 O(n) 或 O(nlog(n)) 或更小。数字在 1 到 1000000 之间。

我的方法是以二进制形式写入每个数字,然后检查数字的每个位是 0 还是 1可以取任意数为 0*(any number) = 0。但我的时间复杂度是 O(n^2),不会通过。

【问题讨论】:

  • 请查看this
  • 那是 O(n^2) 我需要 O(n) 或 O(nlog(n))
  • 我不确定,它可以在少于O(n^2) 的时间内实现。我们需要对数组中的每个数字以及数组中的所有其他数字执行bitwise &。这里的优化是,算法不应该计算已经比较/计算的对。此类优化已在解决方案中到位。
  • 你可以试试Bitwise Trie。虽然分析很复杂 - 它的运行时间将与匹配的数量成正比。如果您的数据集包含大量数字且大部分为 0 位,则它会运行得更慢。
  • 你没有提到n,而是作为主导函数的参数:请明确,包括报告给出0&结果的对数计数他们。

标签: algorithm bitwise-and


【解决方案1】:

我将从给定的数组构建一个 二进制 树,这样每个位都将定义我们在树中是向左还是向右。对于三位数字 101,它将是:

节点--> (1) 右 --> (0) 左 --> (1) 右

(我不知道如何格式化这里的二进制尝试,它会删除所有多个空格,所以我很抱歉这么糟糕的插图)

所以这将花费 O(n)(构建分支和创建新节点是 O(1))。

然后使用递归方法从数组中获取一个数(X),处理它的位并在树上行走,这样对于每个位k

IF (k == num_of_bits)
   Then print pair (X, current node value)
        Return

IF (left branch exists)
    Then take left branch with X[num_of_bits..k+1] // we go left anyway
//ELSE - 'else' here was a mistake
IF X[k] == 0  // if the bit is 0 we can go in both directions
    Then IF (right branch exists)
            Then take right branch with X[num_of_bits..k+1]

现在计算复杂度有点棘手,因为最坏的情况似乎是所有位都是 0,但是在树中你将只有一个分支...... 在我看来,它的复杂性是 O(n*log(n)) - 如果我没有忽略任何东西的话。

所以总共是 O(n) + O(n*log(n)) => O(n*log(n))

【讨论】:

    【解决方案2】:

    您可以使用尝试的概念来解决此问题。

    Insert in trie:首先,将所有数字插入到 trie 树中。这棵树将是一棵二叉树,我们将左孩子作为 0,右孩子作为 1。如果要插入具有二进制表示 001 的 1,则如下:

    根->左(0)->左(0)->右(1)

    如果路径已经存在,请不要再次添加新节点。在这种情况下,只遍历树并在路径不存在的地方添加 0 0r 1 。每个叶子节点也将维护每个数字的计数。因此,插入的时间复杂度将是 O(n*log2(max)),因为我们正在插入 n 个元素,并且每次插入所花费的时间等于数组最大数量的位数。

    在 trie 中查询:对于数组中的每个数字,将数字 n 中的位值与您创建的树上的位进行比较。从数字的第一位开始。

    如果该位为零,则遍历树的右侧或左侧,如果该位为1, 遍历树的左边。

    对数字的每一位执行此操作,直到到达第 n 位。如果您无法恢复第 n 位,则无法返回。如果达到第 n 位,则返回存储在叶节点中的计数。 更详细的解释,参考下面这个链接,

    Trie tree

    【讨论】:

    • @shiram, 如果该位为零,则遍历树的右侧或左侧。您不是说遍历树的左侧(不是或)吗?即我们必须遍历两个子树,因为与位 0 的 AND'ing 在两种情况下都会产生 0,因此两个子树都可能产生一对。如果是这样,查询复杂度将是 O(2^(h+1)) 其中 h 是树高或用于表示我们的数字的最大位数......即给定一个 num==0,我们必须访问每个树中的节点。
    【解决方案3】:

    你可以用这个蛮力

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Scanner;
    
    class BitAnd {
    
    public static void main(String[] args) throws IOException {
        BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
    //  Scanner sc= new Scanner(System.in);             
        int t=Integer.parseInt(br.readLine());
        while(t-->0){
            int n=Integer.parseInt(br.readLine());
            int arr[]= new int[n];
    
            String s[]=br.readLine().split(" ");
            for (int i = 0; i < s.length; i++) {
                arr[i]=Integer.parseInt(s[i]);              
            }
            int c=0;            
            for (int i = 0; i < arr.length; i++) {
                for (int j = i+1; j < arr.length; j++) {
                    if((arr[i]&arr[j])==0)c++;                  
                }               
            }
            System.out.println(c*2);            
        }     
      }
    }
    

    【讨论】:

    • cmets 中已经推荐了这种方法。 Link Here
    猜你喜欢
    • 2015-12-17
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多