题目描述
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
题意解析:给一个数组,其中有一个数出现的次数大于数组长度的一半,找出并返回该数。
一、排序法
由题意分析可知:
众数出现的个数超过了数组长度的一半,如果将数组进行排序,那么这个众数一定占据了中间位置,也就是下标为n/2的位置一定被该众数占据。
这个思路通过画图可直观的看出来。
在此就直接上代码:
lass Solution {
public:
int majorityElement(vector<int>& nums) {
int len = nums.size();
sort(nums.begin(),nums.end());
return nums[len>>1];
}
};
复杂度分析
时间复杂度:O(nlogn)。将数组排序的时间复杂度为 O(nlogn)。
空间复杂度:O(logn)。使用语言自带的排序算法,需要使用 O(logn)的栈空间。
AC结果
二、哈希表法
题意是查找出现次数超过数组长度一半的数,因此,我们可以将已经遍历的数组的数放入一个哈希表中,元素作为哈希表的key,数字出现的次数作为value,因为哈希表的查找的时间复杂度为O(1)。即用空间换取时间。
在动态更新数组中数字出现的次数时,判断当前遍历数字出现的个数是否超过数组长度的一半,如果超过,则直接返回该数。
具体代码实现:
class Solution {
public:
int majorityElement(vector<int>& nums) {
int len = nums.size();
unordered_map<int,int> tmp;
for(auto& n:nums) {
++tmp[n];
if(tmp[n] > len>>1)
return n;
}
return nums[0];
}
};
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的长度。
空间复杂度:O(n)。哈希表最多包含 n−(n/2)个键值对,所以占用的空间为 O(n)。
AC结果
三、摩尔投票法
再次回顾下题目:寻找数组中超过一半的数字,即该数字出现的次数比数组中其它数字出现次数的总和都大。
也就是说,如果将数组中要查找的众数替换成1,其它数字替换成-1,若让其相加,最后的值肯定大于0。
因此,可以执行以下操作解析题目:
1.设置两个变量res和cnt,res用来保存数组中遍历到的某个数字,cnt表示res当前出现的次数,一开始res保存为数组中的第一个数字,cnt为1.
2.遍历整个数组:
- 如果数字与res保存的数字相同,则++cnt;
- 如果数字与res保存的数字不同,则–cnt;
- 如果出现次数cnt变为0,res进行变化,保存为当前遍历的那个数字,同时把cnt重置为1.
3.遍历完数组中的所有元素即可返回res的值。
具体代码实现:
class Solution {
public:
int majorityElement(vector<int>& nums) {
int res=nums[0],cnt=1,len=nums.size();
for(int i=1;i<len;++i) {
if(nums[i] == res) ++cnt;
else --cnt;
if(!cnt) {
res=nums[i];
cnt=1;
}
}
return res;
}
};
复杂度分析
时间复杂度:由于只需要遍历一次,因此时间复杂度为O(n)。
空间复杂度:因为只需要常数级别的额外空间,所以空间复杂度为O(1)。
AC结果