优化的求众数方法 - 摩尔投票算法(算法思想+求众数的三种方法+摩尔投票算法改进版求众数 II)

摩尔投票算法是一种在线性时间O(n)和空间复杂度O(1)的情况下,在一个元素序列中查找包含最多的元素的典型的流算法。

下面用此算法来解LeetCode的169. 求众数、229. 求众数 II。

一、求众数:

给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。

示例 1:
输入: [3,2,3]
输出: 3

示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2

1.普通方法(二重循环):(此方法在数据量大时,必然消耗时间很大)

class Solution {
    public int majorityElement(int[] nums) {
    	int n = nums.length/2;
        for(int i=0; i n){
                return nums[i];
            }else{
                count = 0;
            }
        }
        return -1;
    }
}

2.排序法:(排序后众数一定出现在索引为nums.length/2的位置上)

import java.util.Arrays;
class Solution {
    public int majorityElement(int[] nums) {
    	Arrays.sort(nums);
        return nums[nums.length/2];
    }
}

3.摩尔投票算法:(时间复杂度为O(n),空间复杂度为O(1))

首先,数组中出现次数大于 [n/2 ]的元素只可能有一个(假设这个数字在数组中一定存在)。摩尔投票算法是扫描整个数组,每次从其中选择两个不相同的数字删除掉,直到最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个

(1)先定义一个基数(数组中可以直接使用索引,下面程序中时i,)和一个计数器(count)。

(2)计数器基数为1,代表已经扫描过nums[0],从索引1的位置开始扫描整个数组(也可以直接从头开始),遇到与基数相同的数加1,遇到不同的数减1。

(3)当计数器为0时,数据被分为两段,前一段数据中被计数的元素数和基数数量是相等的,而后面的数据又满足词频最高的数大于总数一半的情形,因此后面的数据就成为了我们的下一个目标,前面的数据就被舍弃了。

(4)完毕之后索引i记录的那个数就是出现次数最多的数。

class Solution {
    public int majorityElement(int[] nums) {
    	int i = 0;
    	int count = 1;
    	for(int j=1; j

以上程序的测试类:

public class LeetcodeTest {
	public static void main(String[] args) {
		Solution So = new Solution();
		int[] nums = {2,2,1,1,1,2,2};
		System.out.println(So.majorityElement(nums));
	}
}

二、求众数 II

给定一个大小为 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。

示例 1:
输入: [3,2,3]
输出: [3]

示例 2:
输入: [1,1,1,3,3,2,2,2]
输出: [1,2]

要求算法的时间复杂度为 O(n),空间复杂度为 O(1),那么这个题自然就是摩尔投票算法的升级版

扫描整个数组,每次从其中选择三个不相同的数字删除掉,最后留下的就是出现次数超过1/3的数。

(1)同样先定义基数nums[i]、nums[j]和计数器count1,count2,这里我们同样可以推断出在整组数据中出现次数超过 [ n/3 ]的数不多于两个。

(2)扫描整个数组,遇到与基数相同的数为对应计数器加1,遇到不同的数减1。

(3)当计数器count1或count2为0时,对应前面的数据段舍弃,以下一个数为基数继续遍历。

(4)完毕之后索引i、j记录的数就是出现次数超过 [ n/3 ]的数。

import java.util.List;
import java.util.ArrayList;
class Solution {
    public List majorityElement(int[] nums) {
        List res = new ArrayList();
        int i = 0; 
        int j = 1;
        int count1 = 0;
        int count2 = 0;
        for(int k=0; k nums.length/3){
        	res.add(nums[i]);
        }
        if(count2 > nums.length/3){
        	res.add(nums[j]);
        }
        return res;
    }
}

测试类:

public class LeetcodeTest {
	public static void main(String[] args) {
		Solution So = new Solution();
		int[] nums = {1,1,1,3,3,2,2,2};
		List res = So.majorityElement(nums);
		System.out.println(res);
	}
}

 

你可能感兴趣的:(leetcode,java)