所有对按位OR求和

时间:2016-08-25 16:01:11

标签: bit-manipulation bit bitwise-or

是否有算法在线性时间复杂度中找到按位OR或数组?

假设数组是{1,2,3},那么所有对的总和id 1 | 2 + 2 | 3 + 1 | 3 = 9。

我可以使用以下算法在O(n)中找到所有对AND和....如何更改此以获得所有对OR和。

int ans = 0;  // Initialize result

// Traverse over all bits
for (int i = 0; i < 32; i++)
{
    // Count number of elements with i'th bit set
    int k = 0;  // Initialize the count
    for (int j = 0; j < n; j++)
        if ( (arr[j] & (1 << i)) )
            k++;

    // There are k set bits, means k(k-1)/2 pairs.
    // Every pair adds 2^i to the answer. Therefore,
    // we add "2^i * [k*(k-1)/2]" to the answer.
    ans += (1<<i) * (k*(k-1)/2);
}

从这里开始:http://www.geeksforgeeks.org/calculate-sum-of-bitwise-and-of-all-pairs/

1 个答案:

答案 0 :(得分:4)

你可以在线性时间内完成。这个想法如下:

  1. 对于每个位位置,记录数组中该位设置为1的条目数。在您的示例中,您有2个条目(1和3),其中1位设置,2个条目具有2位设置(2和3)。
  2. 对于每个数字,通过单独查看每个位并使用缓存的总和来计算数字的按位OR与数组中所有其他数字的总和。例如,考虑总和1 | 1 + 1 | 2 + 1 | 3 = 1 + 3 + 3 = 7.

    因为1的最后一位是1,所以按位或1的结果将最后一位设置为1.因此,所有三个数字1 | 1,1 | 2和1 | 3将具有最后一位等于1.其中两个数字的两位设置为1,这正是将两位设置为1的元素数。通过将这些位分组,我们可以得到总和3 * 1(三位) )+ 2 * 2(两个两位)= 7.

  3. 对每个元素重复此过程可以计算数组中所有有序元素对的所有按位ors的总和。所以在你的例子中,将计算1 | 2和2 | 1,1 | 1也是如此。所以你必须减去像1 | 1这样的所有情况,然后除以2来计算重复计算。

  4. 让我们试试这个算法。

    1. 以二进制编写数字,{1,2,3} = {01,10,11}。一个位设置有2个数字,2个位设置为2个。

    2. 对于01,我们得到3 * 1 + 2 * 2 = 7的总和。

    3. 对于10,我们得到2 * 1 + 3 * 2 = 8的总和。
    4. 对于11,我们得到3 * 1 + 3 * 2 = 9的总和。
    5. 总结这些,7 + 8 + 9 = 24.我们需要减去1 | 1 = 1,2 | 2 = 2和3 | 3 = 3,因为我们在总和中计算了这些。 24-1-2-3 = 18。
    6. 最后,当我们计算两次像1 | 3这样的东西时,我们需要除以2. 18/2 = 9 ,正确的总和。
    7. 该算法为O(任何数组元素中n *最大位数)。

      编辑:我们可以通过简单地从所有对中减去所有0-0对的计数来修改您的发布算法,以获得每个位位置的所有0-1或1-1对。像这样:

      int ans = 0;  // Initialize result
      
      // Traverse over all bits
      for (int i = 0; i < 32; i++)
      {
          // Count number of elements with i'th bit not set
          int k = 0;  // Initialize the count
          for (int j = 0; j < n; j++)
              if ( !(arr[j] & (1 << i)) )
                  k++;
      
          // There are k not set bits, means k(k-1)/2 pairs that don't contribute to the total sum, out of n*(n-1)/2 pairs.
          // So we subtract the ones from don't contribute from the ones that do.
      
          ans += (1<<i) * (n*(n-1)/2 - k*(k-1)/2);
      }