给定n个非负整数的数组:A1,A2,...,AN。如何找到一对整数Au,Av(1≤u 示例:设N = 4,数组为[2 4 8 10]。这里的答案是8 解释 如果N可以达到10 ^ 5,该如何做到这一点。
我有O(N ^ 2)解决方案。但效率不高 代码:2 and 4 = 0
2 and 8 = 0
2 and 10 = 2
4 and 8 = 0
4 and 10 = 0
8 and 10 = 8
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(arr[i] & arr[j] > ans)
{
ans=arr[i] & arr[j];
}
}
}
答案 0 :(得分:4)
你可以加速它的一种方法是利用这样一个事实,即如果任何两个数字中的任何一个高位被设置,那么这两个数字的AND总是大于使用低位的任何组合。 / p>
因此,如果您按照设置的顺序对数字进行排序,则可能会大幅减少操作次数。
为了有效地找到最重要的位,GCC有一个内置的内在函数:__builtin_clz(unsigned int x)
,它返回最重要的设置位的索引。 (其他编译器具有类似的内在函数,至少转换为x86上的单个指令。)
const unsigned int BITS = sizeof(unsigned int)*8; // Assuming 8 bit bytes.
// Your implementation over.
unsigned int max_and_trivial( const std::vector<unsigned int> & input);
// Partition the set.
unsigned int max_and( const std::vector<unsigned int> & input ) {
// For small input, just use the trivial algorithm.
if ( input.size() < 100 ) {
return max_and_trivial(input);
}
std::vector<unsigned int> by_bit[BITS];
for ( auto elem : input ) {
unsigned int mask = elem;
while (mask) { // Ignore elements that are 0.
unsigned int most_sig = __builtin_clz(mask);
by_bits[ most_sig ].push_back(elem);
mask ^= (0x1 << BITS-1) >> most_sig;
}
}
// Now, if any of the vectors in by_bits have more
// than one element, the one with the highest index
// will include the largest AND-value.
for ( unsigned int i = BITS-1; i >= 0; i--) {
if ( by_bits[i].size() > 1 ) {
return max_and_trivial( by_bits[i]);
}
}
// If you get here, the largest value is 0.
return 0;
}
此算法仍然具有最差情况运行时O(N * N),但平均来说它应该表现得更好。当您搜索较小的向量时,您还可以通过重复分区步骤来进一步提高性能(只需记住忽略分区步骤中的最高位,这样做可以将性能提高到最坏的O(N)情况)。
保证输入数据中没有重复项将进一步提高性能。
答案 1 :(得分:3)
注意:如果您发现只有最大元素介于2 ^ k和2 ^(k + 1)之间且第二大元素小于2 ^ k,那么您将不会删除任何元素,而只是减去2 ^ k来自最大元素。
此外,确定元素在系列{1,2,4,8,16,...}中的位置可以在O(log(log(MAX)))时间内完成,其中MAX是最大数字数组。
答案 2 :(得分:3)
我没有测试过这个,我不会去。 O(N)存储器和O(N)复杂度。
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;
/*
* The idea is as follows:
* 1.) Create a mathematical set A that holds integers.
* 2.) Initialize importantBit = highest bit in any integer in v
* 3.) Put into A all integers that have importantBit set to 1.
* 4.) If |A| = 2, that is our answer. If |A| < 2, --importantBit and try again. If |A| > 2, basically
* redo the problem but only on the integers in set A.
*
* Keep "set A" at the beginning of v.
*/
pair<unsigned, unsigned> find_and_sum_pair(vector<unsigned> v)
{
// Find highest bit in v.
int importantBit = 0;
for(auto num : v)
importantBit = max(importantBit, highest_bit_index(num));
// Move all elements with imortantBit to front of vector until doing so gives us at least 2 in the set.
int setEnd;
while((setEnd = partial_sort_for_bit(v, importantBit, v.size())) < 2 && importantBit > 0)
--importantBit;
// If the set is never sufficient, no answer exists
if(importantBit == 0)
return pair<unsigned, unsigned>();
// Repeat the problem only on the subset defined by A until |A| = 2 and impBit > 0 or impBit = 0
while(importantBit > 1)
{
unsigned secondSetEnd = partial_sort_for_bit(v, --importantBit, setEnd);
if(secondSetEnd >= 2)
setEnd = secondSetEnd;
}
return pair<unsigned, unsigned>(v[0], v[1]);
}
// Returns end index (1 past last) of set A
int partial_sort_for_bit(vector<unsigned> &v, unsigned importantBit, unsigned vSize)
{
unsigned setEnd = 0;
unsigned mask = 1<<(importantBit-1);
for(decltype(v.size()) index = 0; index < vSize; ++index)
if(v[index]&mask > 0)
swap(v[index], v[setEnd++]);
return setEnd;
}
unsigned highest_bit_index(unsigned i)
{
unsigned ret = i != 0;
while(i >>= 1)
++ret;
return ret;
}
答案 3 :(得分:0)
这是一个O(N * log MAX_A)解决方案:
1)让我们贪婪地构建答案,从最高位迭代到最低位。
2)要做到这一点,人们可以保留当前适合的一组数字。最初,它由数组中的所有数字组成。我们还假设最初ANS = 0。
3)现在让我们迭代从最高到最低的所有位。让我们说当前位是B.
4)如果S中第1位值为1的元素数大于1,则可能在此位置有1而不改变ANS中高位的值,所以我们应该加2 ^ B到ANS并删除S中具有0位值的所有元素(它们不再适合)。
5)否则,在此位置无法获得1,因此我们不会更改S和ANS并继续下一位。