C 通过在数组的2个不同元素上执行按位和运算,找到最大数量的最快、最有效的方法
给定一个非负整数数组,通过对数组中的两个不同元素执行按位and(即,&运算符)可以找到最大个数的最快和最有效的方法是什么 这是我到目前为止的代码: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我希望我的
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,到目前为止,我已经使用了蛮力技术(迭代数组中的每一对不同整数,计算它们的按位