如果数组中一半以上的元素相同,则称数组具有多数元素。是否有一种分治算法来确定数组是否具有多数元素?
我通常会执行以下操作,但它不是使用“分而治之”。我不想使用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;
}
一个更简单的分治算法适用于存在多于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,但必须小心处理边界情况。
是的,它不需要元素有顺序。
从形式上讲,我们处理的是多集(也称为包)在下面,对于多集S,让:
S的多数元素m,如果存在的话,就是2v(m;S)的元素
我们把L和R称为s的分裂⊕ R=S和偶数分裂if |#L-#R |≤ 1.也就是说,如果n=#S是偶数,L和R正好有S元素的一半,如果n是奇数,那么一个有基数[n/2],另一个有基数[n/2]1。
对于S任意拆分为L和R,有两个观察结果:
>
如果L和R中的一个具有多重性k的多数元素m,那么只有当它在另一半具有多重性r时,它才是S的多数元素,具有2(k r)
下面的多数算法返回一对(m,k),表示m是出现k次的多数元素,或者不返回:
>
设(m,k)=多数(L),如果不是无:
a.设k'=k v(m; R)。
b、 返回(m,k'),如果是2k'
否则,令(m, k)=多数(R),如果不是无:
a、 设k'=kv(m;L)。
b、 返回(m,k'),如果是2k'
请注意,即使拆分不是偶数,该算法仍然正确。但在实践中,平均分割可能会表现得更好。
补遗
在上面的算法描述中明确了终端情况。一些示例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;
}
我至少能看到一种分而治之的方法。
从找到中位数开始,例如使用Hoare的Select算法。如果一个值构成了大多数元素,则中位数必须具有该值,因此我们刚刚找到了我们正在寻找的值。
从那里,找到(例如)第25和第75百分位项目。同样,如果有一个多数元素,那么其中至少有一个元素的值必须与中值相同。
假设你还没有排除大多数元素的存在,你可以继续搜索。例如,假设第75百分位等于中位数,但第25百分位不等于。
在第25个百分位数和第75个百分位数之间继续搜索。
继续查找每个分区的中位数,该分区必须包含与中位数值相同的元素结尾,直到确认或否认多数元素的存在。
顺便说一句:我不太明白Boyer Moore将如何用于这项任务。Boyer Moore是一种在字符串中查找子字符串的方法。
我和朋友在讨论是否可以在不排序数组的情况下,使用分治算法计算数组a[1…n]中出现的某个元素k的数量? 我们遇到了一个障碍,如果我们使用二进制搜索,一旦找到元素,它就会停止。有什么想法吗?
主要内容:分治算法的利弊,分治算法的应用场景实际场景中,我们之所以觉得有些问题很难解决,主要原因是该问题涉及到大量的数据,如果只需要处理少量的数据,问题会变得非常容易解决。 举一个简单的例子,设计一个排序算法实现对 1000 个整数进行排序。对于很多刚刚接触算法的初学者来说,直接实现对 1000 个整数进行排序是非常困难的。而同样的问题,如果转换成对 2 个整数进行排序,解决起来就很容易。 分治算法中,“分治”即“分而治之”的意思。分治算法
几周前我有一个工作面试,我被要求设计一个分而治之的算法。我无法解决这个问题,但他们只是打电话给我进行第二次面试!问题是: 我们给出了两个n元素数组A[0..n-1]和B[0..n-1](它们不一定是排序的),以及一个整数值作为输入。给出了一个O(nlogn)分治算法,该算法确定是否存在不同的值i,j(即i!=j),使得A[i]+B[j]=value。如果i,j存在,算法应返回True,否则返回Fa
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [3,2,3] 输出: 3 示例 2: 输入: [2,2,1,1,1,2,2] 输出: 2 实现如下: /** * @param {number[]} nums * @return {n
我有一个问题,试图实现一个算法使用分而治之。 给定一个未排序的数组tv[]查找该数组的de v[k]元素,就好像该数组已排序,但没有对数组v排序一样。 例如,如果k=3且v={2,-1,-6,7,4},则该数组的k元素为2。 因为我无法编辑传递的数组,所以我无法想出另一种方法来对数组进行排序,而不将其保存在另一个局部变量上,或者尝试像快速排序一样分割数组,并返回v的最后一个元素的位置。 如果有帮助
我在分而治之的算法上遇到了一点麻烦,正在寻找一些帮助。我试图编写一个名为sumArray的函数,它计算整数数组的和。 此函数必须通过将数组一分为二并对每一半执行递归调用来完成。我曾尝试使用类似的概念,当我编写递归和算法和分治算法来识别数组中的最大元素时,我使用了这些概念,但我很难将这两个想法结合起来。 下面是我为sumArray编写的代码,它编译,但没有返回正确的结果。