如果超过一半的元素是相同的,则称一个数组具有多数元素。是否存在用于确定数组是否具有多数元素的分而治之算法?
我通常会做以下事情,但它并没有使用分而治之。我不想使用Boyer-Moore算法。
int find(int[] arr, int size) {
int count = 0, i, mElement;
for (i = 0; i < size; i++) {
if (count == 0) mElement = arr[i];
if (arr[i] == mElement) count++;
else count--;
}
count = 0;
for (i = 0; i < size; i++) {
if (arr[i] == mElement) count++;
}
if (count > size / 2) return mElement;
return -1;
}
答案 0 :(得分:4)
我至少可以看到一种分而治之的方法。
首先查找中位数,例如使用Hoare的Select算法。如果一个值构成了元素的大多数,则中位数必须具有该值,因此我们只是找到了我们正在寻找的值。
从那里,找到(例如)第25和第75百分位数的项目。同样,如果有多数元素,那么至少有一个元素需要与中位数具有相同的值。
假设您还没有排除多数元素,您可以继续搜索。例如,让我们假设第75百分位数等于中位数,但第25百分位数不是。
然后继续搜索第25百分位数和中位数之间的项目,以及第75百分位数和结束点之间的中间位置。
继续查找每个分区的中位数,该分区必须包含与中位数相同的元素的结尾,直到您确认或否认存在多数元素为止。
顺便说一句:我不太清楚Boyer-Moore将如何用于此任务。 Boyer-Moore是一种在字符串中查找子字符串的方法。
答案 1 :(得分:3)
有,并且不需要元素有订单。
为了正式,我们正在处理multisets(也称为 bags 。)在下文中,对于多集 S ,请:
S 的多数元素 m (如果存在)是2 v ( m 的元素>; S )&gt; #S
如果 L ,让我们调用 L 和 R S 的拆分 R = S 和甚至拆分如果| #L - #R | ≤1。即,如果 n = #S 是偶数, L 和 R 只有一半的元素 S ,如果 n 是奇数,则其中一个具有基数[ n / 2]而另一个具有基数[ n < / EM> / 2] +1。
对于 S 到 L 和 R 的任意分割,有两个观察结果:
如果 L 和 R 都没有多数元素,则 S 不能:对于任何元素 e ,2 v ( e ; S )= 2 v ( e ; L )+ 2 v ( e ; R )≤ #L + #R = #S 。
如果其中一个 L 和 R 的多数元素 m 具有多重性 k ,那么它只是 S 的主要元素,只要它在另一半中具有多重性 r ,其中2( k + r )&gt; #S
以下算法多数( S )会返回一对( m , k ),表示 m 是 k 出现的主要元素,或 none :
设( m , k )= 多数( L ),如果不是无:
一个。设 k' = k + v ( m ; R )。
湾如果2 k'&gt;则返回( m , k') 名词
否则让( m , k )= 多数( R ),如果不是< EM>无:
一个。设 k' = k + v ( m ; L )。
湾如果2 k'&gt;则返回( m , k') 名词
请注意,即使拆分不是偶数,算法仍然正确。实际上,均匀分裂可能会表现得更好。
<强>附录强>
在上面的算法描述中明确了终端案例。一些示例C ++代码:
struct majority_t {
int m; // majority element
size_t k; // multiplicity of m; zero => no majority element
constexpr majority_t(): m(0), k(0) {}
constexpr majority_t(int m_,size_t k_): m(m_), k(k_) {}
explicit operator bool() const { return k>0; }
};
static constexpr majority_t no_majority;
size_t multiplicity(int x,const int *arr,size_t n) {
if (n==0) return 0;
else if (n==1) return arr[0]==x?1:0;
size_t r=n/2;
return multiplicity(x,arr,r)+multiplicity(x,arr+r,n-r);
}
majority_t majority(const int *arr,size_t n) {
if (n==0) return no_majority;
else if (n==1) return majority_t(arr[0],1);
size_t r=n/2;
majority_t left=majority(arr,r);
if (left) {
left.k+=multiplicity(left.m,arr+r,n-r);
if (left.k>r) return left;
}
majority_t right=majority(arr+r,n-r);
if (right) {
right.k+=multiplicity(right.m,arr,r);
if (right.k>r) return right;
}
return no_majority;
}
答案 2 :(得分:0)
更简单的分而治之算法适用于存在多于1/2个元素的情况,对于某个整数k,存在n = 2 ^ k个元素。
FindMost(A, startIndex, endIndex)
{ // input array A
if (startIndex == endIndex) // base case
return A[startIndex];
x = FindMost(A, startIndex, (startIndex + endIndex - 1)/2);
y = FindMost(A, (startIndex + endIndex - 1)/2 + 1, endIndex);
if (x == null && y == null)
return null;
else if (x == null && y != null)
return y;
else if (x != null && y == null)
return x;
else if (x != y)
return null;
else return x
}
可以修改此算法,使其适用于非指数为2的n,但必须小心处理边界情况。
答案 3 :(得分:0)
让我们说阵列是1,2,1,1,3,1,4,1,6,1。
如果一个数组包含多于一半的元素,那么应该有一个两个连续元素相同的位置。
在上面的例子中,观察1重复超过一半。并且索引(索引从0开始)索引2和索引3具有相同的元素。