剑指Offer 39. 数组中出现次数超过一半的数字 - Touale Cula's Blog

题目内容

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

1
2
3
4
5
6
7
8
9
示例?1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
?

限制:

1 <= 数组长度 <= 50000

解法一: 哈希表(暴力法)

思路:利用map存储,后遍历取出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int,int> cmap;
for(int num:nums){
cmap[num] += 1;
}
auto iter =cmap.begin();
while(iter != cmap.end())
{
if( iter->second>nums.size()/2){
return iter->first;
}
++iter;
}
return 0;
}
};

结果:

1
2
3
4
5
6
7
8
9
10
11
12
执行用时:
12 ms
, 在所有 C++ 提交中击败了
88.49%
的用户
内存消耗:
18.4 MB
, 在所有 C++ 提交中击败了
18.38%
的用户
通过测试用例:
45 / 45

此法继续优化,在第一个循环时检查是否超过一半,超过直接退出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int,int> cmap;
int temp = nums.size()/2;
for(int num:nums){
cmap[num] += 1;
if(cmap[num]>temp)return num;
}
auto iter =cmap.begin();
while(iter != cmap.end())
{
if( iter->second>temp){
return iter->first;
}
++iter;
}
return 0;
}
};

效率提升一般

1
2
3
4
5
6
7
8
9
10
11
12
执行用时:
12 ms
, 在所有 C++ 提交中击败了
88.49%
的用户
内存消耗:
18.3 MB
, 在所有 C++ 提交中击败了
67.94%
的用户
通过测试用例:
45 / 45

解法二:排序

思路:既然超过一半,中位数应该就是目标

1
2
3
4
5
6
7
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size()/2];
}
};
1
2
3
4
5
6
7
8
9
10
11
12
执行用时:
12 ms
, 在所有 C++ 提交中击败了
88.49%
的用户
内存消耗:
18.2 MB
, 在所有 C++ 提交中击败了
96.60%
的用户
通过测试用例:
45 / 45

解法三:摩尔投票法

思路:见 心法_摩尔投票法

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public:
int majorityElement(vector<int>& nums) {

int x = 0,votes = 0;
for(int num:nums){
if(votes==0)x=num;
votes += num == x ? 1: -1;
}
return x;

}
};

结果

1
2
3
4
5
6
7
8
9
10
11
12
执行用时:
8 ms
, 在所有 C++ 提交中击败了
98.07%
的用户
内存消耗:
18.4 MB
, 在所有 C++ 提交中击败了
22.42%
的用户
通过测试用例:
45 / 45