给定一组非负整数,找到最大值的最快和最有效的方法是什么。可以通过在数组的2个DISTINCT元素上执行按位和(即&运算符)来获得?
这是我的代码,直到现在:
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
}
}
这当然是天真的方法。我正在寻找更有效的解决方案。
也许类似于使用trie(实际上是二叉树)来查找数组元素的最大XOR。有关max XOR解决方案的说明,请访问http://threads-iiith.quora.com/Tutorial-on-Trie-and-example-problems?share=1
答案 0 :(得分:4)
我希望我的问题是正确的。这是我的解决方案:
你有一个整数数组,说它们是无符号整数,因为我们处理的是按位运算。让我们把它们看作是一串零和一的二进制表示,然后把它们放在一起。
我们现在将它们相应的位垂直对齐。让我们从最左边的列开始绘制垂直线。如果我们在列中遇到多于或等于两个1
,则排除没有1
s的每一行。在绘制我们的垂直线时,我们将忽略被排除的那些。
你看到这是怎么回事?
这将继续下去,直到我们只剩下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;
}
行动期间的情况相同:http://ideone.com/hRA8tn
我不确定这是否是最好的,但它应该比全部测试更好。
答案 1 :(得分:0)
首先看一下并理解heapsort算法。
将数组转换为堆,使您可以访问两个最大的元素。这是在线性时间O(n)内完成的。
取两个最大的元素,x =最大,y =第二大。如果y = 0,则解为0.如果x中的最高位和y中的最高位相同,则解是x&amp;年。否则,清除x中的最高位,修复堆,然后重试。最后一步采用O(log 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.
如果i≠j,则假设a [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 log n),例如,如果除0之外的所有元素都是1。
答案 2 :(得分:0)
以下内容适用于我our_n
uint our_a[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) ;
,但不更改数组或复制数据或其他任何内容。本质上是在一次向下传递数组时,它标识了到目前为止可以添加到结果的下一位。每次传递仅考虑包含到目前为止结果的所有位的值:
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 ;
所以,这是O(p * n),其中p是通过次数:1..32。
如果可以销毁数组的内容,那么内部循环可以更改为:
{{1}}
当然,第一遍现在正在做更多的工作而不是需要,所以单独这样做可以节省更多。