剑指offer39-数组中出现次数超过一半的数字

数组中出现次数超过一半的数字叫众数
注意数学中众数指数组中出现次数最多的数字

方法一:暴力解法

遍历并计数

var majorityElement = function(nums) {
    const map = new Map();
    for(const item of nums){
        map.set(item, (map.get(item) || 0) + 1);
    }
    for(const [key, value] of map.entries()){
        if(value > nums.length / 2){
            return key;
        }
    }
}

方法二:数组排序返回中位数

Javascript内置Array对象sort方法
sort() 方法用于对数组的元素进行排序,排序顺序可以是字母或数字,并按升序或降序
时间复杂度O(nlogn)
空间复杂度O(1)

var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
console.log(numbers);

也可以写成:
var numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => a - b);
console.log(numbers);

// [1, 2, 3, 4, 5]

本题解法

var majorityElement = function(nums) {
    nums.sort((a,b) => a - b);
    return nums[Math.floor(nums.length / 2)];
}
const majorityElement = nums => {
    nums.sort((a, b) => a - b);
    return nums[nums.length >> 1];
}

可参考
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
https://www.runoob.com/jsref/jsref-sort.html


方法三:摩尔投票法

算法流程
初始化:票数统计votes=0,众数res;
循环:遍历数组nums中的每个数字num;
当票数votes等于0,则假设当前数字num是众数;
当num=res时,票数votes自增1;当 num!=x时,票数votes自减1;
返回值:返回res即可;

时间复杂度O(n)
空间复杂度O(1)

var majorityElement = function(nums) {
    var vote = 0, selectNum = 0;
    for(const item of nums){
        if(vote === 0){
            selectNum = item;
        }
        vote += item === selectNum ? 1 : -1;
    }
    return selectNum;
}
var majorityElement = function(nums) {
    let ans = 0, count = 0;
    for(let i = 0; i < nums.length; i++){
        if(!count) {
            ans = nums[i];
            count++;
        }else count += nums[i] === ans ? 1 : -1;
    }
    return ans;
}
var majorityElement = function (nums) {
  // 代表结果的众数
  let res;
  // 统计票数
  let votes = 0;
  for (let i = 0; i < nums.length; i++) {
    // 刚开始是0票,所以把数组的第一个元素作为众数
    // 如果以后的循环votes票数被抵消掉了为0,那么下一个元素就作为众数
    if (votes == 0) {
      res = nums[i];
    }
    // 和当前众数相同的,那么票数就加1
    if (res == nums[i]) {
      votes++;
    } else {
      // 如果和当前票数不同,票数就被抵消掉了一个
      votes--;
    }
  }
  return res;
}

拓展 由于题目说明给定的数组总是存在多数元素,因此本题不用考虑数组不存在众数的情况。若考虑,需要加入一个验证环节,遍历数组nums统计res的次数。若res的数量超过数组长度一半,则返回res;否则,返回0。

注意 摩尔投票法找的其实不是众数,而是占一半以上的数。当数组没有超过一半的数,则可能返回非众数,比如[1, 1, 2, 2, 2, 3, 3],最终返回3。投票法简单来说就是不同则抵消,占半数以上的数字必然留到最后。


方法四:哈希表

先码住还不太会 -.-

var majorityElement = function(nums) {
    /* 
        解题思路
        1. 求出一半长度 巧用位运算 max = nums.length >> 1
        2. 构造哈希表 hash: { k: 1 // type:number 该k出现的次数 k即为数组项值 }
        3. 遍历构造hash 过程中当 hash[num] > max 退出循环 直接返回期望值 return num
    */
    const max = nums.length >> 1, 
          hash = Object.create(null)

    for (const num of nums) {
        hash[num] ? hash[num]++ : (hash[num] = 1)
        if (hash[num] > max) return num
    }
}
var majorityElement = function(nums) {
    var res = {};
    for(var i = 0; i < nums.length; i++) {
        if (res[nums[i]]) res[nums[i]]++;
        else res[nums[i]] = 1;
    }
    var max = 0;
    var t = null;
    Object.keys(res).map(k => {
        if (max < res[k]) {
            max = res[k];
            t = k;
        }
    });
    return t;
}

方法五:分治

先码住还不太会 -.-

var majorityElement = function(nums) {
    return findMajorElement(nums, 0, nums.length - 1);
};
var findMajorElement = function(arr, low, high) {
    // base
    if (low === high) {
        return arr[low];
    }
    // divide
    var mid = low + Math.floor((high - low) >> 1);
    var leftMajorNum = findMajorElement(arr, low, mid);
    var rightMajorNum = findMajorElement(arr, mid + 1, high);
    // conquer
    var leftMajorNumCount = countNum(arr, low, high, leftMajorNum);
    var rightMajorNumCount = countNum(arr, low, high, rightMajorNum);
    return leftMajorNumCount > rightMajorNumCount ? leftMajorNum : rightMajorNum;

}
var countNum = function(arr, low, high, target) {
    var count = 0;
    for (var i = low; i <= high; i++) {
        if (arr[i] === target) count++;
    }
    return count;
}

以上内容整理自力扣

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值