leetcode-169. Majority Element

leetcode-169. Majority Element


Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.

题目大意:
给定一个大小为n的数组,找到大多数元素。大多数元素是出现超过⌊n / 2⌋次的元素。 您可能会认为该数组是非空的,而且大多数元素始终存在于数组中。

题目本身还是容易的,主要是记录一下各种解法:


解法一:HashMap

我们可以使用一个HashMap来将元素映射到value上,以便通过在数字上循环来计算线性时间的出现次数。然后,我们只需返回最大值的key。

class Solution {
    private Map<Integer, Integer> countNums(int[] nums) {
        Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
        for (int num : nums) {
            if (!counts.containsKey(num)) {
                counts.put(num, 1);
            }
            else {
                counts.put(num, counts.get(num)+1);
            }
        }
        return counts;
    }

    public int majorityElement(int[] nums) {
        Map<Integer, Integer> counts = countNums(nums);

        Map.Entry<Integer, Integer> majorityEntry = null;
        for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
            if (majorityEntry == null || entry.getValue() > majorityEntry.getValue()) {
                majorityEntry = entry;
            }
        }

        return majorityEntry.getKey();
    }
}

方法二:排序

这个是比较好的方法,将数组排序后,出现超过半数的元素,肯定是length/2位置的元素

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

方法三:随机

这种方法也不是很难理解,但是时间复杂度的证明是比较困难的,也就是为什么没有超时。。
该方法的思路是既然所求的元素在数组中出现的次数超过半数,那么我们随机取数的话,取到的元素也很有可能就是所求的元素。
每次随机取一个数,然后遍历整个数组,计算出现的次数是否超过半数,如果不超过半数就继续取值,直到取到结果为止。

class Solution {
    private int randRange(Random rand, int min, int max) {
        return rand.nextInt(max - min) + min;
    }

    private int countOccurences(int[] nums, int num) {
        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == num) {
                count++;
            }
        }
        return count;
    }

    public int majorityElement(int[] nums) {
        Random rand = new Random();

        int majorityCount = nums.length/2;

        while (true) {
            int candidate = nums[randRange(rand, 0, nums.length)];
            if (countOccurences(nums, candidate) > majorityCount) {
                return candidate;
            }
        }
    }
}

方法四:分治法

将数组分成两部分,寻找第一个部分中出现次数超过一半的元素为A,第二个部分出现次数超过一半的元素为B,如果A==B,那么A就是这个数组中出现次数超过一半的元素,如果A!=B,那么A和B都可能是这个数组中出现次数超过一半的元素,那么重新遍历这个数组,记录A和B出现的次数,返回出现次数多的元素,时间复杂度T(n)=2T(n/2)+2n=O(nlogn)

T(n)=2T(n2)+2n

根据 主定理,循环满足条件2,所以得:
T(n)=Θ(n logbalogn)=Θ(n logn)

public static void main(String[] args) {
    int majorityElement(vector<int>& nums) {

        return helper(nums,0,nums.size()-1);
    }

    helper(vector<int> nums,int begin,int end){
        if(begin == end)
            return nums[begin];
        else{
            int mid = begin + (end-begin)/2;
            int left = helper(nums,begin,mid);
            int right = helper(nums,mid+1,end);
            if(left == right) return left;
            else{
                int leftCount = 0;
                int rightCount = 0;
                for (int i = begin;i<=end ;i++ ) {
                    if (nums[i] == left) 
                        leftCount++;
                    else if(nums[i] == right)
                        rightCount++;
                }

                if (leftCount<rightCount) 
                    return right;
                else return left;
            }   
        }       
    }
}

方法五:Boyer-Moore Voting Algorithm

建议! 读过思路后,阅读一下solution 代码,再回想一下思路 !,就比较容易理解。
这种方法的思路是:每次从数组中找出一对不同的数字,将他们从数组中删除,当最后肯定至少剩下一个元素(3个元素的情况下)(!保证数组中一定存在出现次数超过半数的数字)。
那怎么找到一对不同的数字?怎么删除呢?
在算法的执行过程中,使用一个常量空间来记录候选元素 c 以及他出现的次数 f(c) , c 即为当前阶段出现超过半次的元素(当前阶段指在遍历数组的过程中的 前i个元素)。
在开始之前,c 为第一个元素, f(c)0,然后开始遍历数组:
 如果数组A[i] == c,即元素相同,则f(c)+=1
 如果数组A[i] !== c,即元素不相同,则 f(c)-=1,即删除这个元素的计数。
 如果元素相同或者计数为0,则应该更新元素并将计数加1。
对于两个不同元素,在遍历过后就会使计数器重新变回0,就相当于删除了两个不同元素!
 在遍历的过程中,如果 f(c) = 0,表示当前并没有候选的元素存在;如果f(c)!=0就是在当前阶段存在候选元素(元素在当前阶段出现超过半数),那么他在剩余的字符串中出现的次数也用超过半数,所以方法是可行的。

int majorityElement(vector<int>& nums) {
    int count=0;
    int result=nums[0];
    for(int i=0;i<nums.size();i++)
    {
        if(count==0||nums[i]==result)
        {
            count++;
            result=nums[i];
        }
        else
            count--;
    }
    return result;
}

本来最后f(c) > 0的元素可能并不是出现半次以上的元素,比如{1,2,3},需要遍历数组确认是否出现超过半次,但是题目保证存在出现半次以上的元素,就不用考虑了。

转载于:https://www.cnblogs.com/linkcode/p/8150769.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值