多数元素的求解(JavaScript)

319 阅读2分钟

本文记录了对在数组中出现次数大于 ⌊ n/2 ⌋ 的元素求解的体会,希望能和读者朋友一起进步^_^

个人理解

在做题的时候遇到的问题,自问自答^_^

  1. “多数元素” 等同于众数?

    有的文章直接说求众数,我觉得它们不是等价的。

    众数是指次数出现最多的元素,题目的 “多数元素" 是指出现大于 [n/2]的元素

    有众数不一定存在 “多数元素”; 存在 “多数元素”,那这个数,也一定是众数

    所以本题的有的解法,通过求众数来得到 “多数元素”, 是因为题目假设了 “多数元素” 一定存在

题目介绍

/*
 * @lc app=leetcode.cn id=169 lang=javascript
 *
 * [169] 多数元素
 *
 * https://leetcode-cn.com/problems/majority-element/description/
 *
 * algorithms
 * Easy (63.65%)
 * Likes:    647
 * Dislikes: 0
 * Total Accepted:    182.2K
 * Total Submissions: 286.1K
 * Testcase Example:  '[3,2,3]'
 *
 * 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
 * 
 * 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
 * 
 * 
 * 
 * 示例 1:
 * 
 * 输入: [3,2,3]
 * 输出: 3
 * 
 * 示例 2:
 * 
 * 输入: [2,2,1,1,1,2,2]
 * 输出: 2
 * 
 * 
 */

解零、暴力法 T(n) = O(n^2)

遍历每个元素,再统计每个元素,出现的次数,次数最大的,就是众数,也就是 “多数元素”,T(n) = O(n^2)

解一、排序法 T(n) = O(nlogn)

由于题目假设存在 “多数元素”,且“多数元素”指出现次数大于 n/2,所以排序后,中间元素就肯定是 “多数元素”

代码如下:

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

解二、类 Map 容器 T(n) = O(n) S(n) = O(n)

空间换时间的思路,用到的变量如下:

一个 Map 容器,用于叠加每个元素出现的次数

一个记录最大次数的变量

一个记录最大数的变量

代码如下:

/**
 * @param {number[]} nums
 * @return {number}
 */
var majorityElement = function(nums) {
    const map = {};  // <num.toString(), number>
    let max = 0,
        maxNum;
    for (let i = 0; i < nums.length; i++) {
        const num = nums[i];
        if (map[num] == null) {
            map[num] = 1;
        } else {
            map[num] = map[num] + 1;
        }
        if (map[num] > max) {
            maxNum = num;
            max = map[num];
        }
    }
    return maxNum;
}

解三、摩尔投票法 T(n) = O(n) S(n) = O(1)

维护候选人的次数(抵消或叠加或替换)

“多数元素” 大于 n/2,准备一个候选人,极端情况下,其他元素都用来抵消 “多数元素” ,也至少剩 1 个 “多数元素”

“多数元素” 大于 n/3,准备两个候选人,候选人A > n/3, 候选人B > n/3, 其他 < n/3

本题只需要求 大于 n/2, 所以只要准备一个候选人,代码如下:

/**
 * @param {number[]} nums
 * @return {number}
 */
var majorityElement = function(nums) {
    const candidate = {
        num: null,
        times: 0,
    }
    for (let i = 0; i < nums.length; i++) {
        const num = nums[i];
        if (candidate.num === num) {
            candidate.times += 1;
            continue;
        }
        if (candidate.times > 0) {
            candidate.times -= 1;
        } else {
            candidate.times = 1;
            candidate.num = num;
        }
    }
    return candidate.num;
}