数组中出现次数超过一半的数字——剑指offer 39

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

数组中出现次数超过一半的数字——剑指offer 39_第1张图片

方法1 hash表统计法

var majorityElement = function(nums) {
     
    var map={
     };
    var len=Math.floor(nums.length/2);
    for(var i=0;i<nums.length;i++){
     
        if(map[nums[i]]==null){
     
            map[nums[i]]=1;
        }else{
     
            map[nums[i]]=map[nums[i]]+1;
        }
        if(map[nums[i]]>len){
     
            return nums[i];
        }
    }
};

方法2 摩尔投票法

  • 票数和: 由于众数出现的次数超过数组长度的一半;若记 众数 的票数为 +1 ,非众数 的票数为 −1 ,则一定有所有数字的 票数和 > 0。
  • 票数正负抵消: 设数组 nums 中的众数为 x ,数组长度为 n。若 nums 的前 a 个数字的 票数和 = 0,则 数组后 (n-a)个数字的 票数和一定仍 >0 (即后 (n-a) 个数字的 众数仍为 x )。

算法原理

  • 为构建正负抵消,假设数组首个元素 n1 为众数,遍历统计票数,当发生正负抵消时,剩余数组的众数一定不变 ,这是因为(设真正的众数为 x ):

    • 当n1=x:抵消的所有数字中,有一半是众数x,
    • 等n1≠x:抵消的所有数字中,少于或等于一半是众数x
  • 利用此特性,每轮假设都可以 缩小剩余数组区间 。当遍历完成时,最后一轮假设的数字即为众数(由于众数超过一半,最后一轮的票数和必为正数)。

算法流程:

  1. 初始化: 票数统计 votes = 0 , 众数 x;
  2. 循环抵消: 遍历数组 nums 中的每个数字 num ;
    当 票数 votes 等于 0 ,则假设 当前数字 num 为 众数 x ;
    当 num = x 时,票数 votes 自增 1 ;否则,票数 votes 自减 1 。
  3. 返回值: 返回 众数 x 即可。
var majorityElement = function(nums) {
     
    var votes=0;
    for(var i=0;i<nums.length;i++){
     
        if(votes==0)
            most=nums[i];
        if(nums[i]==most){
     
            votes++;
        }else{
     
            votes--;
        }       
    }
    return most;
};

你可能感兴趣的:(算法,算法)