Fastest and most efficient way to find the maximum no. that can be obtained by performing bitwise and on 2 DISTINCT elements of array

时光总嘲笑我的痴心妄想 提交于 2019-12-12 14:00:53

问题


Given an array of non-negative integers, what is the fastest and most efficient way to find the maximum no. that can be obtained by performing bitwise and (i.e, & operator) on 2 DISTINCT elements of the array?

This is my code until now :

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
    }
 }

This, of course, is the naive method. I am looking for a more efficient solution.

Maybe something like using a trie(actually a binary tree) to find max XOR of elements of array. The description for the max XOR solution can be found at http://threads-iiith.quora.com/Tutorial-on-Trie-and-example-problems?share=1


回答1:


I hope I have got the question right. Here's my solution to it:

You have an array of integers, say that they are unsigned integers since we are dealing with bitwise operations. Let's think of them as a string of zeroes and ones in their binary representation and then put them on top of each other.

We now have their corresponding bits aligned vertically. Let's draw vertical lines, starting from the leftmost column. If we ever encounter more than or equal to two 1s in a column, then rule out every row that does not have the 1s. We are to disregard the ruled out ones while drawing our further vertical lines.

You see where this is going at?

This shall go on until we have only and exactly 2 lines left that hasn't been ruled out. If we ever end up with anything else than 2, then it means something went wrong:

  • Less than 2 means we had less than 2 lines initially
  • More than 2 means that...
    • If there are less than what we had initially, then the ones left should all be identical
    • If there are exactly as many as we had initially, then it can be that all are the same, or every possible pair is bitwise distinct, meaning that every single pair produces 0

Here's the code I've written that follows the logic I've described above:

#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;
}

Here's the same during action: http://ideone.com/hRA8tn

I'm not sure if this is the best, but it should be better than testing all out.




回答2:


First look at and understand the heapsort algorithm.

Turn the array into a heap which lets you access the two largest elements. This is done in linear time, O (n).

Take the two largest elements, x = largest, y = second largest. If y = 0, the solution is 0. If the highest bit in x and the highest bit in y are the same, the solution is x & y. Otherwise, clear the highest bit in x, fix the heap, and try again. The last step takes O (log n) steps, and if you are using k bit integers, like 32 or 64, it is repeated at most k times.

No extra space needed, and linear time.

Pseudo-code:

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. 

This assumes that a [i] and a [j] are considered "distinct array elements" if i ≠ j. If you require instead that a [i] ≠ a [j] then things are slightly different. You'd have to remove duplicate entries in your array, but in case the largest elements are for example 31 and 15, you don't want to clear the highest bit in 31 and then remove it as a duplicate! So the code is more difficult.

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. 

Worst case is O (n log n), for example if all elements are 1 except one that is 0.




回答3:


The following worked for me for our_n uints in uint our_a[our_n], without changing the array or copying it or anything else. The essence is that in one pass down the array it identifies the next bit that can be added to the result so far. Each pass only considers values which contain all the bits of the result so far:

  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) ;

So, this is O(p * n), where p is the number of passes: 1..32.

If it is OK to destroy the contents of the array, then the inner loop can be changed to:

      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 ;

Of course, the first pass is now doing rather more work than it need to, so doing that separately saves a bit more.



来源:https://stackoverflow.com/questions/24978796/fastest-and-most-efficient-way-to-find-the-maximum-no-that-can-be-obtained-by-p

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!