116 lines
3.8 KiB
JavaScript
116 lines
3.8 KiB
JavaScript
/**
|
||
*https://leetcode.cn/problems/majority-element/description/?envType=study-plan-v2&envId=top-interview-150
|
||
* @param {number[]} nums
|
||
* @return {number}
|
||
*/
|
||
const majorityElement = function (nums) {
|
||
f1(nums);
|
||
f2(nums);
|
||
f3(nums, 0, nums.length - 1);
|
||
f4(nums);
|
||
};
|
||
|
||
/*
|
||
暴力法,遍历所有元素,统计每一个元素出现的次数,之后再遍历统计的结果,统计结果中大于数组长度二分之一的就是我们要找
|
||
的多数元素
|
||
*/
|
||
function f1(nums) {
|
||
const countMap = new Map();
|
||
|
||
// 遍历数组,统计数组元素中每个元素出现的次数
|
||
for (const num of nums) {
|
||
countMap.set(num, (countMap.get(num) || 0) + 1);
|
||
}
|
||
|
||
// 遍历countMap 找到出现次数大于数组长度一半的元素就是多数元素
|
||
const majorityCount = nums.length / 2;
|
||
for (const [num, count] of countMap) {
|
||
if (count > majorityCount) return num;
|
||
}
|
||
|
||
// 如果没有就返回, 根据题目要求,不会发生这一情况
|
||
return null;
|
||
}
|
||
|
||
/*
|
||
排序法, 按照题目要求,多数元素一定会大于数组长度的一半, 所以只要把数组拍一个需,那么在1/2位置的元素一定是多数
|
||
元素,why? 我们可以这样思考,想象大脑里面有一个进度条,进度条现在是51%,移动进度条的颜色部分,无论怎么移动,这个
|
||
颜色部分总是会覆盖中间位置, 这里以数组长度3和4为例,如果数组长度是3那么中间元素就是 3/2 = 1.5,但在js中不会自动
|
||
丢弃小数位,所以要Math.floor()向下取整,再来看看四,如果有多数元素,这个多数元素一定有三个,4/2 = 2,刚好也符合,所以
|
||
奇偶无需特殊处理
|
||
*/
|
||
function f2(nums) {
|
||
// 先对数组排序
|
||
nums.sort((a, b) => a - b);
|
||
return nums[Math.floor(nums.length / 2)];
|
||
}
|
||
|
||
/*
|
||
分治法,把大问题化成小问题,把原数组分成左右两部分,找出左右俩部分多数的数,如果这两个数相同就返回这个数,如果
|
||
不相同,再比较谁多,返回多的那个
|
||
*/
|
||
|
||
/**
|
||
*
|
||
* @param {number[]} nums 原数组
|
||
* @param {number} left 开始的部分
|
||
* @param {number} right 结束的部分
|
||
*/
|
||
function f3(nums, left, right) {
|
||
// 如果left和right相等表明只有一个元素,直接返回即可
|
||
if (left === right) return nums[left];
|
||
|
||
// 递归计算左右两部分的多数元素
|
||
const mid = Math.floor((left + right) / 2);
|
||
const leftMajority = f3(nums, left, mid);
|
||
const rightMajority = f3(nums, mid + 1, right);
|
||
|
||
// 如果左右两边的元素相同,则返回这个元素
|
||
if (leftMajority === rightMajority) return leftMajority;
|
||
|
||
// 如果两个元素不相等,就比较它们谁出现的次数多
|
||
const leftMajorityCount = countInRange(nums, left, mid, leftMajority);
|
||
const rightMajorityCount = countInRange(nums, mid + 1, right, rightMajority);
|
||
return leftMajorityCount > rightMajorityCount ? leftMajority : rightMajority;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {number[]} nums 要处理的元素组
|
||
* @param {number} left 左边界
|
||
* @param {number} right 右边界
|
||
* @param {number} target 要统计的目标元素
|
||
* @description 统计目标元素出现的次数
|
||
*/
|
||
function countInRange(nums, left, right, target) {
|
||
let count = 0;
|
||
for (let i = left; i <= right; i++) {
|
||
if (nums[i] === target)count++;
|
||
}
|
||
return count;
|
||
}
|
||
|
||
/*
|
||
投票法:假设数组中举行选择,这样的话,多数元素肯定会选举胜利,如果当前选择的元素和自己是一样的那么就投票,不是就反对
|
||
是对手票减少一个
|
||
*/
|
||
|
||
function f4(nums) {
|
||
if (nums.length === 1) return nums[0];
|
||
let count = 1;
|
||
let num = nums[0]; // 候选的
|
||
for (let i = 1; i < nums.length; i++) {
|
||
if (nums[i] === num) {
|
||
count++;
|
||
} else if (count > 0) {
|
||
count--;
|
||
} else {
|
||
num = nums[i];
|
||
count = 1;
|
||
}
|
||
}
|
||
return num;
|
||
}
|
||
|
||
majorityElement([2, 2, 1, 1, 1, 2, 2]);
|