一、题目
给定一个大小为 n
的数组 nums
,返回其中的多数元素。
多数元素是指在数组中出现次数大于[n/2]
的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:nums = [3,2,3]
输出:3
示例 2:
输入:nums = [2,2,1,1,1,2,2]
输出:2
二、思路
- 本题的关键就是用什么方法统计元素出现的次数,由此会引出多种解法。
① 参考前面题目的先排序后处理 思路,在这里也可以先进行排序,一个很有用的信息是,我们要找的多数元素,出现次数必须≥n/2,这意味着排序后的中位数一定就是这个多数元素。
②Boyer-Moore 投票算法:这种算法的核心思想是通过"投票"机制来找到多数元素。每个元素都可以看作是一张票,投给当前的候选元素。
- 当遇到相同的元素时,计数器增加,表示支持当前候选元素的票数增加。
- 当遇到不同的元素时,计数器减少,表示反对当前候选元素的票数增加。
- 当计数器为 0 时,说明当前没有候选元素,可以选择当前元素作为新的候选元素。
在这道题中:
- 设置一个计数器
count
,初始值为 0。 - 设置一个候选元素
candidate
,初始值为null
。
对于数组中的每个元素 num,
如果 num
不等于当前候选元素 candidate
,将 count
减 1。如果 num
等于当前候选元素 candidate
,将 count
加 1。如果 count
为 0,说明当前没有候选元素,将 num
设为候选元素。
③ 可以用哈希表来简化问题(主要是降低时间复杂度)。这里的映射很明显就是数组元素和元素出现次数之间的映射,也就是可以借助哈希表中的键值对匹配来判断出现次数要不要+1.具体见后续的代码。
三、代码
解法一:先排序后处理
① JavaScript:
javascript
function countTimes(nums){
let n = nums.length;
nums.sort((a,b)=>a-b);
return nums[Math.floor(n/2)];
//这里的Math.floor可以确保结果是一个整数,即向下取整。
}
② C++:
cpp
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
③ Python:
python
def majorityElement(nums]):
nums.sort()
return nums[len(nums) // 2]
解法二:Boyer-Moore投票算法
① JavaScript:
javascript
function countTimes(nums){
let major = null
let count = 0
for (let num of nums) {
if (count === 0) {
major = num
}
if (major === num) {
count++
} else {
count--
}
}
return major
}
② C++:
cpp
int countTimes(const std::vector<int>& nums) {
int major = 0;
int count = 0;
for (int num : nums) {
if (count == 0) {
major = num;
}
if (major == num) {
count++;
} else {
count--;
}
}
return major;
}
③ Python:
python
def count_times(nums):
major = None
count = 0
for num in nums:
if count == 0:
major = num
if major == num:
count += 1
else:
count -= 1
return major
解法三:哈希表
① JavaScript:
javascript
function countTimes (nums) {
let hashTable = {};
let n = nums.length;
// 遍历数组,统计每个元素的出现次数
for (let num of nums) {
if (hashTable[num] == null) {
hashTable[num] = 1;
} else {
hashTable[num]++;
}
}
// 找到出现次数大于 n/2 的元素
for (let num in hashTable) {
if (hashTable[num] > Math.floor(n / 2)) {
return parseInt(num);
}
}
return null; // 如果没有多数元素,返回 null
};
② C++:
cpp
int countTimes(const std::vector<int>& nums) {
unordered_map<int, int> hashtable;
int n = nums.size();
// 遍历数组,统计每个元素的出现次数
for (int num : nums) {
hashtable[num]++;
}
// 找到出现次数大于 n/2 的元素
for (const auto& pair : hashtable) {
if (pair.second > n / 2) {
return pair.first;
}
}
return -1; // 如果没有多数元素,返回 -1
}
③ Python:
python
def count_times(nums):
# 使用 Counter 统计每个元素的出现次数
counter = Counter(nums)
n = len(nums)
# 找到出现次数大于 n/2 的元素
for num, count in counter.items():
if count > n / 2:
return num
return None # 如果没有多数元素,返回 None
四、反思
-
之前并不了解Boyer-Moore投票算法,从这道题来看该算法很适合用于高性能要求/内存限制高的题目;
-
一定要抓住题目中的信息,比如这道题中的n/2,想清楚以后可以简化我们的代码(帮助我们确定中位数一定也就是众数,也就是多数元素)。