C 通过在数组的2个不同元素上执行按位和运算,找到最大数量的最快、最有效的方法

C 通过在数组的2个不同元素上执行按位和运算,找到最大数量的最快、最有效的方法,c,arrays,bit-manipulation,C,Arrays,Bit Manipulation,给定一个非负整数数组,通过对数组中的两个不同元素执行按位and(即,&运算符)可以找到最大个数的最快和最有效的方法是什么 这是我到目前为止的代码: max = 0 for(i=0; i<n; i++) { for(j=i+1; j<n; j++) { temp = a[i] & a[j]; if(temp > max) max = temp } } max=0 对于(i=0;i我希望我的

给定一个非负整数数组,通过对数组中的两个不同元素执行按位and(即,&运算符)可以找到最大个数的最快和最有效的方法是什么

这是我到目前为止的代码:

max = 0
for(i=0; i<n; i++)
{
    for(j=i+1; j<n; j++)
    {
        temp = a[i] & a[j];
        if(temp > max)
            max = temp
    }
 }
max=0

对于(i=0;i我希望我的问题是正确的。以下是我的解决方案:

你有一个整数数组,假设它们是无符号整数,因为我们处理的是按位运算。让我们把它们看作是二进制表示中的一个由0和1组成的字符串,然后把它们放在一起

现在,我们将它们对应的位垂直对齐。让我们从最左边的列开始绘制垂直线。如果我们在一列中遇到超过或等于两个
1
s,则排除没有
1
s的每一行。在绘制进一步的垂直线时,我们将忽略排除的行

你知道这是怎么回事吗

这将持续下去,直到我们只剩下2行没有被排除。如果我们最后得到的不是2行,那就意味着出了问题:

  • 小于2意味着我们最初只有不到2行
  • 超过2意味着。。。
    • 如果没有我们最初拥有的那么多,那么剩下的应该都是一样的
    • 如果有和我们最初一样多的,那么可能是所有的都是相同的,或者每个可能的对都是按位不同的,这意味着每个对都产生
      0
下面是我编写的代码,它遵循我上面描述的逻辑:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <memory.h>

#define bit(_x_) (1U << (_x_))

void randomfillarray( unsigned int * arr, size_t size ) {
    srand( time( NULL ) );
    for ( int i = 0; i < size; i++ )
        arr[i] = rand( );
}

int main( ) {
    unsigned int arr[10];
    size_t size = sizeof arr / sizeof * arr;
    randomfillarray( arr, size );

    unsigned int * resultantcouple = malloc( sizeof arr );
    memcpy( resultantcouple, arr, sizeof arr );

    for ( int i = 0; i < size; i++ )
        printf( i ? " %u" : "%u", arr[i] );
    putchar( '\n' );

    int success = 0;

    for ( unsigned int thebit = bit( sizeof( int ) * 8 - 1 ); thebit; thebit >>= 1 ) {
        int count = 0;
        int * indices = NULL;
        for ( int i = 0; i < size; i++ ) {
            if ( resultantcouple[i] & thebit ) {
                indices = realloc( indices, ++count * sizeof * indices );
                indices[count - 1] = i;
            }
        }
        if ( count >= 2 ) {
            size = count;
            for ( int i = 0; i < size; i++ )
                resultantcouple[i] = resultantcouple[indices[i]];
            resultantcouple = realloc( resultantcouple, size * sizeof * resultantcouple );
        }
        if ( size == 2 ) {
            success = 1;
            break;
        }
        free( indices );
    }

    if ( success )
        printf( "Success! %u and %u are the ones.", resultantcouple[0], resultantcouple[1] );
    else
        printf( "Failure! Either all pairs are bitwise distinct, or there are less than 2 elements, or something else..." );


    putchar( '\n' );
    return 0;
}
#包括
#包括
#包括
#包括
#定义位(1U>=1){
整数计数=0;
int*索引=NULL;
对于(int i=0;i=2){
大小=计数;
对于(int i=0;i
以下是行动中的相同情况:


我不确定这是否是最好的,但它应该比全面测试要好。

首先看看并理解heapsort算法

将数组变成一个堆,允许您访问两个最大的元素。这是在线性时间O(n)内完成的

取两个最大的元素,x=最大,y=第二大。如果y=0,则解决方案为0。如果x中的最高位和y中的最高位相同,则解决方案为x&y。否则,清除x中的最高位,修复堆,然后重试。最后一步需要O(日志n)如果使用k位整数,如32或64,则最多重复k次

不需要额外的空间和线性时间

伪代码:

If n ≤ 1 there is no solution. 
Turn a [0] to a [n-1] into a heap with a [0] as the largest element. 
Repeat
    Let x = a [0].
    Let y = a [1].
    If n ≥ 3 and a [2] > a [1] then let y = a [2].
    If y = 0 then the solution is 0.
    Determine b = the highest bit of x.
    If (y & b) != 0 then the solution is x & y.
    Replace a [0] with x & (~ b)
    Turn a [0] to a [n-1] into a heap again by moving a [0] down. 
这假设a[i]和a[j]被视为“不同的数组元素”,如果i≠ j、 如果您要求a[i]≠ a[j]那么情况就稍有不同了。你必须删除数组中的重复项,但如果最大的元素是31和15,你不想清除31中的最高位,然后将其作为重复项删除!因此代码更难编写

Let mask = ~0. In the following, when creating a heap compare a [i] & mask, not a [i].
Turn a [0] to a [n-1] into a heap with a [0] as the largest element. 
Repeat
    If n ≤ 1 then there is no solution.
    Let x = a [0].
    Let y = a [1].
    If n ≥ 3 and a [2] & mask > y & mask then let y = a [2].

    If x = y then let n = n - 1, let a [0] = a [n], restore the heap, and continue.
    If (y & mask) = 0 then the solution is 0.
    Determine b = the highest bit of x & mask.
    If (y & b) != 0 then the solution is x & y.
    Replace mask with mask & ~b.
    Restore the heap and continue. 

最坏的情况是O(n logn),例如,如果除了一个为0的元素外,所有元素都是1。

以下内容适用于
我们的
uint我们的[our\n]
,无需更改数组或复制数组或其他任何内容。其本质是,在一次向下传递数组时,它标识到目前为止可以添加到结果中的下一位。每次传递仅考虑包含到目前为止结果的所有位的值:

  uint result ;
  uint passes ;
  uint msb ;
  uint pn ;

  at->start_clock = times(&at->start_tms) ;

  result = 0 ;
  passes = 0 ;
  msb    = (UINT_MAX >> 1) + 1 ;
  pn     = our_n ;

  do
    {
      uint seen_once ;
      uint seen_again ;

      passes += 1 ;

      seen_once  = 0 ;
      seen_again = 0 ;

      for (uint i = 0 ; i < pn ; ++i)
        {
          uint a ;

          a = our_a[i] ;

          if ((a & result) == result)
            {
              seen_again |= (a & seen_once) ;
              seen_once  |= a ;
            } ;
        } ;

      assert((seen_again & result) == result) ;

      seen_again ^= result ;

      while (msb > seen_again)
        msb >>= 1 ;

      result |= msb ;
    }
  while (msb > 1) ;
uint结果;
uint通行证;
uint-msb;
uint pn;
at->start\U clock=次数(&at->start\U tms);
结果=0;
通过率=0;
msb=(UINT_MAX>>1)+1;
pn=我们的n;
做
{
你没见过你一次;
你再也见不到你了;
通过次数+=1;
见过一次=0;
再次看到_=0;
对于(uint i=0;i再次查看)
msb>>=1;
结果|=msb;
}
而(msb>1);
这是O(p*n),其中p是通过的次数:1..32

如果可以销毁数组的内容,则可以将内部循环更改为:

      k = 0 ;
      for (uint i = 0 ; i < pn ; ++i)
        {
          uint a ;

          a = our_a[i] ;

          if ((a & result) == result)
            {
              our_a[k++] = a ;

              seen_again |= (a & seen_once) ;
              seen_once  |= a ;
            } ;
        } ;
      pn = k ;
k=0;
对于(uint i=0;i

当然,第一关现在做的工作比需要的要多,所以单独做会节省更多。

如果您添加一些代码并分享您的想法和尝试,这可能是一个好问题。@barakmanos,到目前为止,我已经使用了蛮力技术(迭代数组中的每一对不同整数,计算它们的按位