持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
题目(Majority Element)
链接:https://leetcode-cn.com/problems/majority-element
解决数:2943
通过率:66.8%
标签:数组 哈希表 分治 计数 排序
相关公司:amazon google microsoft
给定一个大小为 n **的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: nums = [3,2,3]
输出: 3
示例 2:
输入: nums = [2,2,1,1,1,2,2]
输出: 2
提示:
n == nums.length1 <= n <= 5 * 104-109 <= nums[i] <= 109
进阶: 尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
思路1,哈希表
- 思路:循环数组,用哈希表存储数字和对应的个数,如果数字出现的个数大于
n/2则返回这个数 - 复杂度分析:时间复杂度:
O(n),n为nums数组的长度。空间复杂度:O(n),哈希表需要的空间
代码:
var majorityElement = function (nums) {
let half = nums.length / 2;
let obj = {};
for (let num of nums) {
obj[num] = (obj[num] || 0) + 1;
if (obj[num] > half) return num;
}
};
思路2,抵消
代码:
//[1,1,2,2,2]
const majorityElement = nums => {
let count = 1;
let majority = nums[0];
for (let i = 1; i < nums.length; i++) {
if (count === 0) {
majority = nums[i];
}
if (nums[i] === majority) {
count++;
} else {
count--;
}
}
return majority;
};
思路3,分治
- 思路:不断从数组的中间进行递归分割,直到每个区间的个数是1,然后向上合并左右区间个数较多的数,向上返回。
- 复杂度分析:时间复杂度:
O(nlogn),不断二分,复杂度是logn,二分之后每个区间需要线性统计left与right的个数,复杂度是n。空间复杂度:O(logn),递归栈的消耗,不断二分。
代码:
var majorityElement = function (nums) {
const getCount = (num, lo, hi) => {//统计lo到hi之间num的数量
let count = 0;
for (let i = lo; i <= hi; i++) {
if (nums[i] === num) count++;
}
return count;
};
const getMode = (lo, hi) => {
if (lo === hi) return nums[lo];
//拆分成更小的区间
let mid = Math.floor((lo + hi) / 2);
let left = getMode(lo, mid);
let right = getMode(mid + 1, hi);
if (left === right) return left;
let leftCount = getCount(left, lo, hi);//统计区间内left的个数
let rightCount = getCount(right, lo, hi);//统计区间内right的个数
return leftCount > rightCount ? left : right;//返回left和right中个数多的那个
};
return getMode(0, nums.length - 1);
};