没有输出的输入是不完整的

0%

剑指offer-数组中出现次数超过一半的数字

本文为剑指 offer 系列第二十九篇。
主要知识点为数组,找出数组中出现次数超过一半的数字,两种方式解决这个问题。map计数和两军对决。

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

解题思路

思路1

找个map来存储每个字符出现的次数,然后遍历一遍map找到次数大于一半的数字即可。

思路2

可以想象成战场厮杀,要找的数字为红方,其他为蓝方,红蓝双方士兵实力相等,一换一。由于要找的数字出现次数超过一半,所以厮杀结束之后剩下的必然是我们要找的数字。
回到本题目中来,我们按照数组顺序来依次上场,保存当前场上的序号和次数,若下一个字符和当前场上字符一致,则出现次数+1,若不一致,则-1,若次数减为0,则场上的人由下一次人来替换,出现次数变为1.等到所有的数据都遍历结束,则剩下的就是可能是结果的数据,然后计算该数据在整个数组中出现的次数,判断是否符合出现次数超过一般的条件,若符合,返回target,否则返回0。
以a = {1,2,3,2,2,2,5,4,2}为例。

  1. 索引为0时。保存target = 1,time = 1;
  2. 索引为1时,由于a[1]!= target, 所以原来target出现的次数要减1,保存target = 1, time = 0;
  3. 索引为2时,由于time = 0,所以更新target = 3,time = 1;
  4. 索引为3时,a[3] = 2与target不一致,所以更新target = 3,time = 0;
  5. 索引为4时,target = 2,time = 1;
  6. 索引为5时,target = 2,time = 2;
  7. 索引为6时,target = 2,time = 1;
  8. 索引为7时,target = 2,time = 0;
  9. 索引为8时,target = 2,time = 1;

所以2是一个可能的解,然后在数组中计算target 2出现次数为5,超过数组长度的一半,所以返回target2.

解题代码

思路1代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
unordered_map<int,int> mmap;
for(auto a:numbers){
mmap[a]++;
}
int temp = numbers.size()/2;
for(auto a:mmap){
if(a.second> temp) return a.first;
}
return 0;
}
};

时间复杂度为O(n),空间复杂度为O(n)

思路2代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
// 方法2: 两军对决
int target = 0,time = 0;
for(int i = 0; i < numbers.size(); i++){
if(time == 0){
target = numbers[i];
time = 1;
}else if(target != numbers[i]){
time--;
}else{
time++;
}
}
time = count(numbers.begin(),numbers.end(),target);
return time>numbers.size()/2?target:0;
}
};

时间复杂度为O(n),空间复杂度为O(1)
以上,本题结束!