【问题标题】:Divide-and-conquer algorithm for finding the majority element?寻找多数元素的分而治之算法?
【发布时间】:2018-10-16 04:45:15
【问题描述】:

如果一个数组的一半以上元素相同,则称该数组具有多数元素。是否有分治算法来确定数组是否具有多数元素?

我通常会执行以下操作,但它不使用分而治之。我不想使用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;
}

【问题讨论】:

  • 你为什么不想使用 Boyer-Moore,它是如此高效?
  • 我实际上想使用分而治之算法,因为这个原因我不希望使用博耶-摩尔算法
  • 我不认为这是一个好主意:如果将数组分成两半,最频繁的元素可能不是两半中最频繁的元素。例如,CCCAAAAABBBBBCCC。
  • @YvesDaoust:该示例没有多数元素(多数元素在 16 次中至少出现 9 次)。
  • @MSalters:同样的限制适用于多数元素:它不会在所有细分中都是多数派,而且 D&Q 的重复并不简单。

标签: c++ algorithm


【解决方案1】:

我可以看到至少一种分而治之的方法。

首先找到中位数,例如使用 Hoare 的 Select 算法。如果一个值构成了大部分元素,则中位数必须具有该值,因此我们刚刚找到了我们正在寻找的值。

从那里,找到(例如)第 25 和第 75 个百分位数的项目。同样,如果存在多数元素,则其中至少有一个需要与中位数具有相同的值。

假设您尚未排除存在多数元素,您可以继续搜索。例如,假设第 75 个百分位等于中位数,但第 25 个百分位不等于。

然后继续搜索第 25 个百分位和中位数之间的项目,以及第 75 个百分位和末尾之间的那个项目。

继续查找每个分区的中位数,该中位数必须包含与中位数相同的元素的末尾,直到您确认或否认存在多数元素。

顺便说一句:我不太明白 Boyer-Moore 将如何用于这项任务。 Boyer-Moore 是一种在字符串中查找子字符串的方法。

【讨论】:

【解决方案2】:

有,而且不需要元素有顺序。

正式地说,我们正在处理multisets(也称为bags。)在下面,对于多重集S,让:

  • v(e,S) 是元素eS中的多重性,即它出现的次数(如果e根本不是S的成员,则多重性为零。)
  • #SS 的基数,即 S 中的元素个数计数多重性。
  • ⊕ 是多集和:如果 S = LR 那么 S 包含所有元素LR计数重数,即v(e;S) = v(e;L) + v(e;R) 用于任何元素 e。 (这也说明多重性可以通过‘分而治之’来计算。)
  • [x]是小于等于x的最大整数。

S 的多数元素 m,如果存在的话,是那个元素,使得 2 v(m;S) > #S.

我们称 LRS分裂 如果 LR = S 和一个偶分裂 if |#L - #R| ≤ 1。即如果 n=#S 是偶数,则 LR 正好有一半的元素S,如果 n 是奇数,则一个具有基数 [n/2] 而另一个具有基数 [n/2]+1.

对于将 S 任意拆分为 LR,有两个观察结果:

  1. 如果 LR 都没有多数元素,则 S 不能:对于任何元素 e em>, 2 v(e;S) = 2 v(e ;L) + 2 v(e;R) ≤ #L + #R = #S.

  2. 如果 LR 之一的多数元素 m 具有多重性 k,则它是S的多数元素,只有当它在另一半有多重性r,有2(k+r em>) > #S.

下面的算法 ma​​jority(S) 返回一对 (m,k),表示m 是出现 k 次的多数元素,或者 none

  1. 如果S为空,返回none;如果S只有一个元素m,则返回(m,1)。否则:
  2. S平均分成两半LR
  3. 令 (m,k) = ma​​jority(L),如果不是 none:

    一个。令 k' = k + v(m;R)。 p>

    b.如果 2 k' > n,则返回 (m,k')。

  4. 否则让 (m,k) = ma​​jority(R),如果不是 none

    一个。令 k' = k + v(m;L)。 p>

    b.如果 2 k' > n,则返回 (m,k')。

  5. 否则返回

请注意,即使拆分不是偶数,该算法仍然是正确的。尽管在实践中平均分配可能会表现得更好。

附录

在上面的算法描述中明确了终端情况。一些示例 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;
}

【讨论】:

  • [x] 是楼层函数?
  • [x] 是楼层函数;而m函数的计数也可以分治:count ( m , L ⊕ R ) = count ( m, L ) + count ( m , R),其中 ⊕ 表示多集和。 (我将编辑答案以使其更清楚。)
【解决方案3】:

一个更简单的分治算法适用于存在超过 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,但必须小心处理边界情况。

【讨论】:

  • Size : 4 , Array : 1 2 3 1,应该返回null的时候还是返回1
【解决方案4】:

假设数组是 1、2、1、1、3、1、4、1、6、1。

如果一个数组包含超过一半的元素相同,那么应该有两个连续元素相同的位置。

在上面的例子中,观察 1 重复了一半以上。并且索引(索引从 0 开始)索引 2 和索引 3 具有相同的元素。

【讨论】:

    猜你喜欢
    • 2015-05-03
    • 2020-01-07
    • 2020-05-31
    • 2016-08-16
    • 2013-02-02
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    相关资源
    最近更新 更多