您将获得一个32位无符号整数数组,其长度最多为2 32 ,其中包含数组中一半以上条目的属性等于N,对于某些32位无符号整数N.找到N只查看数组中的每个数字一次并使用最多2 kB的内存。
您的解决方案必须具有确定性,并保证找到N.
答案 0 :(得分:58)
为每个位保留一个整数,并为数组中的每个整数适当增加此集合。
最后,一些位的计数将高于数组长度的一半 - 这些位确定为N.当然,计数将高于N出现的次数,但这不是物。重要的是,任何不属于N 的位都不能出现超过一半的次数(因为N有超过一半的条目),并且任何属于N 的位必须< / em>发生的次数超过一半(因为每次发生N时都会发生,以及任何额外的事件)。
(目前没有代码 - 即将失去网络访问权限。希望上述内容已经足够清楚了。)
答案 1 :(得分:41)
Boyer and Moore's "Linear Time Majority Vote Algorithm" - 沿阵列向下,保持你当前的答案。
答案 2 :(得分:7)
只需两个变量就可以做到这一点。
public uint MostCommon(UInt32[] numberList)
{
uint suspect = 0;
int suspicionStrength = -1;
foreach (uint number in numberList)
{
if (number==suspect)
{
suspicionStrength++;
}
else
{
suspicionStrength--;
}
if (suspicionStrength<=0)
{
suspect = number;
}
}
return suspect;
}
将第一个数字设为可疑号码,然后继续循环浏览列表。如果数字匹配,将怀疑强度提高一个;如果不匹配,请将怀疑强度降低一个。如果怀疑强度达到0,则当前数字成为可疑数字。这将不找到最常见的数字,只有一个超过该组50%的数字。如果suspicionStrength
大于列表长度的一半,则拒绝添加检查的冲动 - 它总是会导致更多的总比较。
P.S。我没有测试过这段代码 - 自己冒险使用它。
答案 3 :(得分:4)
Jon的算法的伪代码(记事本C ++ :-)):
int lNumbers = (size_of(arrNumbers)/size_of(arrNumbers[0]);
for (int i = 0; i < lNumbers; i++)
for (int bi = 0; bi < 32; bi++)
arrBits[i] = arrBits[i] + (arrNumbers[i] & (1 << bi)) == (1 << bi) ? 1 : 0;
int N = 0;
for (int bc = 0; bc < 32; bc++)
if (arrBits[bc] > lNumbers/2)
N = N | (1 << bc);
答案 4 :(得分:2)
请注意,如果序列a0, a1, . . . , an−1
包含一个领导者,那么在删除一对之后
不同值的元素,剩下的序列仍然具有相同的领导者。的确,如果我们
删除两个不同的元素,然后只有其中一个可以成为领导者。领导者
新序列超过n/2 − 1
= (n−2)/2
倍。因此,它仍然是领导者
新的n − 2
元素序列。
这是一个Python实现,具有O(n)时间复杂度:
def goldenLeader(A):
n = len(A)
size = 0
for k in xrange(n):
if (size == 0):
size += 1
value = A[k]
else:
if (value != A[k]):
size -= 1
else:
size += 1
candidate = -1
if (size > 0):
candidate = value
leader = -1
count = 0
for k in xrange(n):
if (A[k] == candidate):
count += 1
if (count > n // 2):
leader = candidate
return leader
答案 5 :(得分:2)
这是流式算法中的一个标准问题(你有一个巨大的(可能是无限的)数据流),你必须从这个流计算一些统计数据,一次通过这个流。
显然,您可以使用散列或排序来处理它,但是如果有可能无限的流,您显然会耗尽内存。所以你必须在这里做一些聪明的事。
多数元素是发生超过数组大小一半的元素。这意味着多数元素的出现次数超过了所有其他元素的组合,或者如果你计算多数元素的次数,并且减去所有其他元素的数量,你将得到一个正数。
因此,如果你计算一些元素的数量,并减去所有其他元素的数量并得到数字0 - 那么你的原始元素就不能成为多数元素。这个如果是正确算法的基础:
有两个变量,计数器和可能的元素。迭代流,如果计数器为0 - 你覆盖可能的元素并初始化计数器,如果数字与可能的元素相同 - 增加计数器,否则减少它。 Python代码:
def majority_element(arr):
counter, possible_element = 0, None
for i in arr:
if counter == 0:
possible_element, counter = i, 1
elif i == possible_element:
counter += 1
else:
counter -= 1
return possible_element
很明显,算法O(n)
在O(n)
之前具有非常小的常数(如3)。此外,空间复杂度似乎为O(1)
,因为我们只初始化了三个变量。问题是这些变量之一是一个可能长到n
的计数器(当数组由相同的数字组成时)。要存储您需要n
空格的O(log (n))
号码。从理论的角度来看 它是O(n)
时间和O(log(n))
空间。 从实际开始,你可以在longint中输入2 ^ 128个数字,并且数组中的元素数量难以想象。
另请注意,只有存在多数元素时,算法才有效。如果这样的元素不存在,它仍然会返回一些数字,这肯定是错误的。 (很容易修改算法来判断多数元素是否存在)
历史频道:这个算法是1982年由Boore,Moore在某处发明的,并称为Boyer–Moore majority vote algorithm。
答案 6 :(得分:0)
我对此算法有一些回忆,它可能会也可能不会遵循2K规则。它可能需要用堆栈等重写,以避免因函数调用而破坏内存限制,但这可能是不必要的,因为它只有这种调用的对数。无论如何,我对大学的模糊回忆或对此的递归解决方案涉及分而治之,秘诀是当你将组分成两半时,至少有一半的一半仍然有一半以上的值等于最大值。除法时的基本规则是返回两个候选顶值,其中一个是最高值,另一个是其他值(可能是也可能不是第二位)。我忘记了算法本身。
答案 7 :(得分:0)
buti-oxa / Jason Hernandez答案的正确性证明,假设Jason的答案与buti-oxa的答案相同,并且两者都按照所描述的算法的方式工作:
如果选择最高值,我们将调整后的怀疑强度定义为等于怀疑强度,或者如果未选择最高值,则将调整后的怀疑强度定义为-suspicion strength。每次选择正确的数字时,当前调整的怀疑强度增加1.每次选错号码时,它会下降1或增加1,具体取决于当前是否选择了错误的数字。因此,最小可能的结束调整后的怀疑强度等于[最高值]的数量 - [其他值]的数量