Advertisement

摩尔投票法寻找众数

阅读量:

要求:输入一个整数数组,找出其中所有出现超过 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)

还没有任何评论哟~