摩尔投票法寻找众数
发布时间
阅读量:
阅读量
要求:输入一个整数数组,找出其中所有出现超过 n/2或者n/3 次的元素并返回。(众数未必存在)
摩尔投票法
摩尔投票法的基本思想是,在每一轮投票过程中,从数组中找出一对不同的元素,将其从数组中删除。这样不断的删除直到无法再进行投票,如果数组为空,则没有任何元素出现的次数超过该数组长度的一半。如果只存在一种元素,那么这个元素则可能为目标元素。
寻找数组中出现个数超过n/2的众数
首先来考虑最简单的情况,寻找个数大于n/2(下取整)的元素,如果存在这样的元素,那么有且只有一个,不能存在两个个数大于n/2个不同的元素,仅这两个元素个数加起来就大于n了。假设如果存在满足条件的众数,从数组中删去不相同的两个元素,不断重复,那么剩下的那个元素就是众数。最差的情况是每次删去的两个元素刚好是一个非众数和一个众数,如果删去的元素是两个非众数,那剩下众数个数相对变多,因为众数个数大于n/2,这样到最后剩下的元素就是众数(如果存在众数),因为他未必存在众数,因此对这个元素进行遍历,来确定其个数是否大于n/2。
举两个简单例子7个元素的数组,众数的个数至少是4,如{1,2,1,3,1,4,1},当遇见两个不同元素就删除,先删除{1,2},再删除{1,3},{1,4}。最后剩下元素1。如果是{1,2,3,4,1,1,1}最后会剩下{1,1,1}。如果是8个元素,众数个数至少为5个,非众数最多就为3个。
具体的算法如下,先用将数组第一个元素赋值给value,计数器初始化为0,遍历整个数组,先检查count1的值,如果为0就重置value的值,并置计数器为1,count1不为0的话,如果和value相等就加一,不等就减一。重复直到遍历结束,用计数器count2来计数数组中值为value的元素个数,来检查是否大于n/2.Java代码如下:
```java
import java.util.Scanner;
public class lookformass {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int num = input.nextInt();
int[] arrary = new int[num];
for(int i = 0; i<num;i++) {
arrary[i]= input.nextInt();
}
input.close();
int value= arrary[0];
int count1 = 0;
for(int i = 0 ; i< num;i++) {
if(count1==0) value = arrary[i];
if(arrary[i]==value) {
count1++;
}
else {
count1--;
}
}
int count2=0;
for(int i = 0 ; i< num;i++) {
if(arrary[i]==value) {
count2++;
}
}
if(count2*2>num)
System.out.print(value);
else
System.out.print("你所输入的数据中没有众数");
}
}
## 寻找数组中出现个数大于n/3的元素
当寻找所有出现次数大于n/3的元素,显然最多只能有两个众数,由两个元素可以类推过来,每次都删除3个不相同的元素,剩下的应该就是众数了。定义a和b来暂存元素,counta和countb为他们的计数器。先将a和b都暂存第一个元素,计数器均置0,遍历数组,先和a比较,如果相等,counta加一,如不等,和b比较,和b相等countb加一,如果均不满足,来看counta是否为0,如果为0,改变a的值,置counta为1,如果counta不为0,来检查countb的值,为0,就改变b的值置countb为1。以上均不满足就将a和b的计数器减一就行了。可以这样来理解,a和b存放是这两个众数,当遍历的元素和a相等,就投a一票,和b相等就投b一票,当计数器为0的时候,说明应该更换众数候选了,如果计数器都不为0,那么就将两个计数器都减一。这一部分代码是
int a=arrary[0], b = arrary[0], counta = 0, countb = 0;
for(int i =0 ; i<num;i++)
{
if(a==arrary[i]) counta++;
else if(b == arrary[i]) countb++;
else if(counta == 0) a=arrary[i], counta = 1;
else if(countb == 0) b=arrary[i], countb = 1;
else counta--,countb--;
}
整个完整的代码是
import java.util.Scanner;
public class lookformasstwo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
System.out.print("请输入元素个数");
int num = input.nextInt();
System.out.print("请依次输入元素");
int[] arrary = new int[num];
for(int i = 0; i<num;i++) {
arrary[i]= input.nextInt();
}
input.close();
int a=arrary[0];
int b = arrary[0];
int counta = 0;
int countb = 0;
for(int i =0 ; i<num;i++)
{
if(a==arrary[i])
counta++;
else if(b == arrary[i])
countb++;
else if(counta == 0) {
a=arrary[i];
counta = 1;
}
else if(countb == 0) {
b=arrary[i];
countb = 1;
}
else {
counta--;
countb--;
}
}
counta = 0;
countb = 0;
for(int i =0 ; i<num;i++) {
if(arrary[i]==a)
counta++;
}
for(int i =0 ; i<num;i++) {
if(arrary[i]==b)
countb++;
}
if(counta*3>num||countb*3>num) {
System.out.println("众数为");
if(counta*3>num)
System.out.println(a);
if(countb*3>num)
System.out.println(b);
}
else
System.out.print("该数组中没有众数");
}
}
# 本题的其他解法
具体可以参照leetcode
169.求众数 https://leetcode-cn.com/problems/majority-element/
222.求众数2https://leetcode-cn.com/problems/majority-element-ii/
全部评论 (0)
还没有任何评论哟~
