这是我的面试问题,我有点难过。给定一个由 k 个元素组成的数组,设计一个线性时间算法来确定列表是否具有多数元素,其中多数元素是在列表中出现超过 k/2 次的元素。
4 回答
您可以使用及时运行的Boyer 算法O(n)
。它通过数组两次。
该算法对多数元素使用初始candidate
值,以及count
初始设置为零的计数器。
第一遍看起来像这样:
int count = 0;
T candidate = null;
foreach (var element in array) {
if (count == 0) {
candidate = element;
count = 1;
} else {
if (candidate == element) {
count++;
} else {
count--;
}
}
}
如果存在多数元素,candidate
则在循环结束时将等于它。但是,如果没有多数元素,则候选可能包含误报。第二遍处理该问题:
count = 0;
foreach (var element in array) {
if (element == candidate) {
count++;
}
}
if (count > array.Length/2) {
Console.WriteLine("Majority element is {0}", candidate);
} else {
Console.WriteLine("No majority element");
}
您可以将数组的元素散列为整数值,其中元素的值是散列的键,散列的值是数组中每个元素出现次数的计数。您还可以将最大出现次数存储为最大值;如果 max > k/2,则列表具有多数元素,您甚至不需要再次遍历哈希。
Robert S Boyer and J Strother Moore wrote an algorithm that finds the majority in O(n) time and O(1) space, and can be used on-line, for instance with data stored on magnetic tape (assuming a single rewind). The idea is to keep at all times a candidate winner, incrementing a count by 1 each time the candidate is seen, decrementing the count by 1 each time some other candidate is seen, and resetting the candidate with the current item whenever the count is zero. The surviving candidate is in the majority, if a majority exists; that requires a separate pass through the data, counting the number of appearances of the candidate. Boyer and Moore (the same guys that wrote the string-matching algorithm) wrote a delightful paper它不仅描述了算法,还描述了他们的 FORTRAN 77 程序的正式证明。我在我的博客中有一个 Scheme 的实现。
Create Hashmap, with elements as keys and counters as values
For each item
If the item doesn't have an entry in the hashmap,
Create a counter, starting with a zero value
Increment the counter stored in the hashmap
If the count > k /2
Then this element is the majority element; return true
There is no max if we reach this line; return false