剑指offer之数组中出现次数超过一半的数字/Leetcode之Majority Element

题目描述

剑指offer:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
Leetcode:
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.

解题思路

方法一:暴力法

遍历数组,依次判断每个元素是否为多数元素
时间复杂度为 O(n2) O ( n 2 ) ,空间复杂度为 O(1) O ( 1 )

方法二:哈希表法

首先创建一个HashMap,遍历数组,利用hashmap记录每个数字以及数字出现的次数
时间复杂度为 O(n) O ( n ) ,空间复杂度为 O(n) O ( n )

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        if(array==null||array.length==0){
            return 0;
        }
        HashMap<Integer,Integer>  map = new HashMap<Integer,Integer>();
        for(int i=0;i<array.length;i++){
            if(map.get(array[i])!=null){
                map.put(array[i],map.get(array[i])+1);
            }else{
                map.put(array[i],1);
            }
            if(map.get(array[i])>array.length/2){
                return array[i];
            }
        }
        return 0;  
    }
}

方法三:排序

先排序,然后找到第n/2个元素即可
时间复杂度为 O(nlogn) O ( n l o g n ) ,空间复杂度为 O(1) O ( 1 ) O(n) O ( n )

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        return nums[nums.size()/2];
    }
};

方法四(推荐):摩尔投票法 Moore Voting

每次取出两个不同的数,剩下的数字中重复出现的数字肯定比其他数字多,将规模缩小化。如果每次删除两个不同的数(不管包括不包括最高频数),那么在剩余的数字里,原最高频数出现的频率一样超过了50%,不断重复这个过程,最后剩下的将全是同样的数字,即最高频数。此算法避免了排序,时间复杂度为 O(n) O ( n ) ,空间复杂度为 O(1) O ( 1 )

举个栗子:有一个士兵和他自己打架就赢一分,和别人打架就输一分,他的分数是零就出局了。从下一个排号的开始(也可能是他自己)再进行以上,一直比到最后还有分的那个,就可能是胜利者(如果这个胜利者是恰巧赢了那几局,就说明那个出现最多的那个士兵并不存在,所以最后重新计数)。

首先第一个for循环结束后得到的num是什么?如果这个数组中存在个数大于数组长度一半的数,那么这个num一定是这个数,因为数组中所有不是num的数,一定会被这个数覆盖,所以最后得到的数是num。但是,如果这个数组中根本不存在个数大于数组长度一半的数,那么这个num就是一个不确定的值,这也是为什么找出num之后,还要再做一次循环验证这个数出现的个数是不是大于数组长度一半的原因。

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int n = numbers.size();
        if (n == 0) return 0;

        int num = numbers[0], count = 1;
        for(int i = 1; i < n; i++) {
            if(numbers[i] == num) 
                count++;
            else 
                count--;
            if(count == 0) {
                num = numbers[i];
                count = 1;
            }
        }
        //验证这个数是否满足条件
        count = 0;
        for (int i = 0; i < n; i++) {
            if (numbers[i] == num) count++;
        }
        if (count << 1 > n) return num;
        return 0;

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值