题目描述
数组中占比超过一半的元素称之为主要元素。给你一个 整数 数组,找出其中的主要元素。若没有,返回 -1 。请设计时间复杂度为 O(N) 、空间复杂度为 O(1) 的解决方案。
使用 map 统计每个元素出现的个数,最终保留出现次数大于 n / 2 n / 2 n/2 的元素,即可。
class Solution {
public int majorityElement(int[] nums) {
int n = nums.length;
Map<Integer, Integer> map = new HashMap<>();
for (int x : nums) {
map.put(x, map.getOrDefault(x, 0) + 1);
if (map.get(x) > n / 2) return x;
}
return -1;
}
}
如果将数组 nums 中的所有元素按照单调递增或单调递减的顺序排序,那么下标为 n u m s . l e n g t h / 2 nums.length / 2 nums.length/2 的元素(下标从 0 开始)一定是众数。
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
}
用 哈希表 来求解本题,不是最好的解法,因为其 空间复杂度为 O ( n ) O(n) O(n)。
此类在一个集合中寻找 多数元素(或,众数)问题,使用 摩尔投票法
可以将 空间复杂度降为 O ( 1 ) O(1) O(1)
摩尔投票法 分为2个阶段:
变量定义:设
cand
为“可能”候选人(即,多数元素),count
为cand
的 “可抵消次数”
count == 0
时,说明之前的候选人 c a n d cand cand 对应的 c o u n t count count 都被抵消完事了,此时需要更换候选人;cand
,不一定是最终 的众数,所以还需要一轮 计算阶段,来判断后选择 cand
是不是最终的“众数”
class Solution {
public int majorityElement(int[] nums) {
int n = nums.length;
int cand = -1;
int count = 0;
// 1、投票阶段
for (int i : nums) {
// 1.1 投票
if (cand == i) { // 相同元素,则累加
count++;
continue;
}
// 1.2 更换候选人
if (count == 0) {
cand = i;
count = 1;
continue;
}
// 1.3 不同元素,则抵消
count--;
}
// 2、计数阶段
int sum = 0;
for (int i : nums) {
if (i == cand ) sum++;
}
if (sum > n / 2) return cand;
else return -1;
}
}
注意⚠️:“投票阶段”三者的顺序不可以改变,否则逻辑则会出现问题
题目描述
参考:题解-摩尔投票法
思路
cand1
和 cand2
,整体代码和 面试题 17.10. 主要元素 板子基本一致。总结:
1
个代表,那他的票数至少要超过一半(⌊ 1/2 ⌋
)的票数;2
个代表,那他们的票数至少要超过 ⌊ 1/3 ⌋
的票数;m
个代表,那他们的票数至少要超过 ⌊ 1/(m+1) ⌋
的票数。class Solution {
public List<Integer> majorityElement(int[] nums) {
List<Integer> res = new ArrayList<>();
int cand1 = -1;
int count1 = 0;
int cand2 = -1;
int count2 = 0;
// 1、投票阶段
for (int num : nums) {
// 1.1 投票
if (num == cand1) { // 相同,则累加
count1++;
continue;
}
if (num == cand2) { // 相同,则累加
count2++;
continue;
}
// 1.2 更换候选人
if (count1 == 0) {
cand1 = num;
count1 = 1;
continue;
}
if (count2 == 0) {
cand2 = num;
count2 = 1;
continue;
}
// 1.3 抵消: 当前元素和两个候选人都不同,则抵消
count1--;
count2--;
}
// 2、计数阶段
int sum1 = 0;
int sum2 = 0;
for (int num : nums) {
if (cand1 == num) sum1++;
else if (cand2 == num) sum2++;
}
if (sum1 > nums.length / 3) {
res.add(cand1);
}
if (sum2 > nums.length / 3) {
res.add(cand2);
}
return res;
}
}
注意⚠️:“投票阶段”三者的顺序不可以改变,否则逻辑则会出现问题
笔记小记
- start
2021/10/23
- update
2022/4/23