每日一题-LeetCode(169)多数元素

116 阅读2分钟

本文首发小呆&小萌的情侣博客,两个前端的学习生活分享小天地,欢迎关注收藏。

今天是小呆刷题的第16天,今天的题目是:力扣(LeetCode)的第169题,多数元素

题目要求

给定一个大小为n的数组nums,返回其中的多数元素。多数元素是指在数组中出现次数大于⌊ n/2 ⌋的元素。

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

示例:

输入:nums = [3,2,3]
输出:3

输入:nums = [2,2,1,1,1,2,2]
输出:2

提示:

  • n == nums.length
  • 1 <= n <= 5 * 104
  • -109 <= nums[i] <= 109

解题思路

这道题小呆的第一思路就是用哈希表来解决,因为跟返回数组中出现次数最多的题的思路是一样的,只不过这道题是返回次数大于n/2的那个元素。

哈希表-多数元素

/**
 * @param {number[]} nums
 * @return {number}
 */
var majorityElement = function(nums) {
  let hasMap = new Map(), half = nums.length / 2

  for(let num of nums) {
    if(hasMap.has(num)) {
      hasMap.set(num, hasMap.get(num) + 1)
    } else {
      hasMap.set(num, 1)
    }
    if(hasMap.get(num) > half) {
      return num
    }
  }
};

习惯性的做完去评论区开拓视野,然后发现了这道题至少有4种解法,除了上面的哈希表,还可以用排序摩尔投票分治来解决,分治目前小呆还没接触过,所以直接跳过,等到学会分治算法之后再回过头来看这道题。其他两种题解分享一下,首先是排序:

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

其次是摩尔投票,摩尔投票的核心就是对拼消耗。评论区你我山巅自相逢同学解释的挺好:

题目中我们需要查找的数字超过数组长度的一半,也就是说,要查找的数字target的个数会超过其他数字个数。

假设不同数字相互抵消,那么最后剩下的数字,就是我们要找的多数元素。

我们可以把这个过程打个比方,比如现在多军对峙,假设阵营A士兵人数比其他方的人数都多,阵营A士兵能以一杀一,那么只要阵营A士兵不杀自己人(相同数字),去杀不同阵营的人(不同数字),那么最后剩下的那些士兵,就是阵营A的士兵。

摩尔投票-多数元素

/**
 * @param {number[]} nums
 * @return {number}
 */
var majorityElement = function(nums) {
  let count = 1
  let majority = nums[0] // 先选择nums[0]所代表的队伍为对拼方
  for(let i = 1; i < nums.length; i++) {
    if(count === 0) {  // 这支队伍暂时没人了可以对拼了,那就先换只队伍
      marjority = nums[i]
    }
    if(nums[i] === majority) { // 友军,拉到我们的队伍里
      count++
    } else {
      count-- // 非友军,对拼消耗
    }
  }
};

小结

今天又学到了一种新算法,摩尔投票法,收获满满!

引用

力扣LeetCode的第169题-多数元素

通俗易懂的摩尔投票法-作者:你我山巅自相逢