LintCode majority numbe (主元素)

LintCode 主元素

主元素
给定一个整型数组,找出主元素,它在数组中的出现次数严格大于数组元素个数的二分之一。

给出数组[1,1,1,1,2,2,2],返回 1
挑战
要求时间复杂度为O(n),空间复杂度为O(1) 。

solution:
对于这个问题,有很多解决的方法。

Method1. 最基本的解决方法
使用两个for循环计算出每个元素出现的次数, 如果该次数大于数组元素的二分之一就返回该元素, 及伪代码为:

//arr[]
n = arr.length;  //数组元素的个数
for i = arr[0] to arr[n-1] 
    count = 0
    for (j = arr[0] to arr[n-1] 
        if (arr[i] == arr[j] and i != j)
            ++count;
    if count > size/2
        return arr[i]

对于该方法,其时间复杂度为 O(n2) , 空间空间复杂度为 O(1)

Method2. 排序
很明显,题目中的意思是该元素一定存在。因此,可以对数组进行排序。那么arr[size/2]一定是该主元素。

 /**
* @param nums: a list of integers
* @return: find a  majority number
*/
public int majorityNumber(ArrayList<Integer> nums) {
    // write your code
    Collections.sort(nums);
    return nums.get(nums.size()/2);
}

注意:该方法只有当主元素一定存在时才有效。
如果使用快速排序对该数组进行原址排序那么其时间复杂度为 O(nlogn) , 空间复杂度为 O(1)

Method3. 使用hashmap
使用HashMap来计算,其中key用来存储元素,而value表示元素出现的次数。

public static int majorityNumber(ArrayList<Integer> nums) {

    Map<Integer, Integer> map = new HashMap<>();
    for (int e : nums) {
        Integer count  = map.get(e);
        count = (count == null ? 1 : count+1);
        if (count > nums.size()/2)
            return e;
        map.put(e, count);
    }

    return -1;
}

很显然写这篇博客的原因,并不是简简单单的为了解决该问题。而是为了学习。在题目中有个挑战:要求时间复杂度为O(n),空间复杂度为O(1) 。因此,Google时发现了Moore’s Voting Algorithm,该算法可以在 O(n) 解决该问题。
因此,以下内容翻译自:GeeksforGeeks Majority Element
该博客中还提到了一种解决该问题的方法,使用二叉查找树。

Method4. 二叉查找树
其中二叉查找树的数据域如下:

struct tree
{
  int element;
  int count;
}BST;

对于每一个元素都保存了一个计数器,用来计数每个元素出现的次数。
因此,对于数组中的元素,一个一个的插入到二叉树中。如果该元素已经存在二叉树中则计数器加一。并且判断该计数器是否大于size/2,如果是则返回该元素,否则继续插入元素。
其中,该方法的最好情况是所有的主元素都在数组中开头的位置。例如:{1, 1, 1, 1, 1, 2, 3, 4}.
时间复杂:对于一般的二叉树为 O(n2) 。 如果使用平衡二叉查找树则时间复杂度为 O(nlogn)

Method5. Moore’s Voting Algorithm
该算法有两个步骤:
1. 获取数组中出现次数最多的元素。这个过程将会确保如果存在一个主元素(majority element), 就讲该元素返回。
2. 检查从上面步奏获取的元素是否是主元素。

(1). 找出候选元素 (finding a Candidate):
我们可以使用Moore’s Voting Algorithm来找出该元素,其时间复杂度为 O(n) 。该算法最基本的思想就是:如果e是一个主元素, 那么我们就可以抵消所有与e不相同的元素对。并且剩下的元素一定是e。
也可以如下理解:

每次都找出一对不同的元素,从数组中删掉,直到数组为空或只有一种元素。 不难证明,如果存在元素e出现频率超过半数,那么数组中最后剩下的就只有e。

Moore’s Voting Algorithm伪代码为:

findCandidate(a[], size)
1.  Initialize index and count of majority element
     maj_index = 0, count = 1
2.  Loop for i = 1 to size – 1
    (a)If a[maj_index] == a[i]
        count++
    (b)Else
        count--;
    (c)If count == 0
        maj_index = i;
        count = 1
3.  Return a[maj_index]

Moore’s Voting Algorithm遍历了每一个元素,并且对元素 a[maj_index] 维持了一个计数器 count ,如果下一个元素与该元素相同那么 count 加1,如果不相同那么 count 减1。如果 count 等于0,那么把当前元素的索引 i 赋值给 maj_index 并且设置 count 为1。

Moore’s Voting Algorithm 算法选出了一个候选元素(candidate element)。那么接下来,我们就要去检查该元素是不是一个majority element。该过程很简单并且很容易在 O(n) 下做到。我们只需要去检查该元素出现的次数是否大于n/2.

例如:
A[] = 2, 2, 3, 5, 2, 2, 6
1). 初始化:
maj_index = 0, count = 1 –> candidate 2 ?

i = 1;
2 = a[maj_index] –> count = 2

i = 2;
3 != a[maj_index] –> count = 1

i = 3;
5 != a[maj_index] –> count = 0
因为,count= 0, 所以改变candidate为5 –> maj_index = 3, count = 1

i = 4;
2 != a[maj_index] —> count = 0 —> candidate 2, maj_index=4, count = 1

i = 5;
2 = a[maj_index] –> count = 2

i = 6;
6 != a[maj_index] –> count = 1

那么就有majority element = 2.

(2). 检查第一步所得到的元素是不是主元素majority element

printMajority (a[], size)
1.  Find the candidate for majority
2.  If candidate is majority. i.e., appears more than n/2 times.
       Print the candidate
3.  Else
       Print "NONE"

注意:Moore’s Voting Algorithm 只有主元素一定存在时该算法才有效,否则该算法返回错误的结果。因此,第二步检查是有必要的!

Talk is cheap, show me the code !

    // Moore’s Voting Algorithm
    private static int findCandidate(ArrayList<Integer> nums) {
        int maj_index = 0, count = 1;
        for (int i = 1; i < nums.size(); ++i) {
            if (nums.get(i).equals(nums.get(maj_index)))
                count++;
            else
                count--;
            if (count == 0) {
                maj_index = i;
                count = 1;
            }
        }

        return nums.get(maj_index);
    }

    private static boolean isMajority(int [] nums, int cand) {
        int count = 0;
        for (int e : nums) {
            if (e == cand)
                ++count;
        }

        return count > nums.length / 2 ;
    }

Moore Voting Alogrithm 可以更加泛化的求解数组中至少出现 n/k 次的元素,详情请看Moore’s Voting Algorithm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值