1.题目描述
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:𝑛≤50000n≤50000,数组中元素的值 0≤𝑣𝑎𝑙≤100000≤val≤10000
要求:空间复杂度:𝑂(1)O(1),时间复杂度 𝑂(𝑛)O(n)
输入描述:
保证数组输入非空,且保证有解
示例1
输入:
[1,2,3,2,2,2,5,4,2]返回值:
2示例2
输入:
[3,3,3,3,2,2,2]返回值:
3示例3
输入:
[1]返回值:
1
2.解题思路
思路1:哈希表
使用哈希表存储每一个数字的出现次数,在遍历的过程中,如果发现了某个数字的出现次数超过数组长度的一半,可以提前break跳出循环
这个方法最为直观,但需要O(n)的额外空间,存储每个元素的出现次数,并非最优解
思路2:候选人选择法(最优解)
我们所求元素为数组中超过了一半的元素,那么它的出现次数一定大于数组中其余元素的出现次数之和,那么我们可以模拟这个选择的过程为一个投票的过程。
首先,我们令数组中的第一个元素nums[0]为候选人,在接下来的遍历过程中,遇到跟它相同的元素时,count+1,表示有人投了赞同票,遇到跟candidate不同的元素时,count-1,表示一个反对票,当count=0时,就需要选择下一个元素作为新的候选人,同时置票数count为初始值1,当遍历结束后,candidate中记录的即为所求
3.代码实现
思路1:
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型一维数组
* @return int整型
*/
public int MoreThanHalfNum_Solution (int[] numbers) {
// write code here
int res = 0;
int n = numbers.length;
if (n == 1) return numbers[0];
Map<Integer,Integer> map = new HashMap<>();
for (int num : numbers) {
if (map.containsKey(num)) {
int val = map.get(num) + 1;
map.put(num,val);
if (val > n/2) {
res = num;
break;
}
} else {
map.put(num,1);
}
}
return res;
}
}
思路2:
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型一维数组
* @return int整型
*/
public int MoreThanHalfNum_Solution (int[] numbers) {
// write code here
int candidate = numbers[0];
int count = 1;
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] == candidate) {
count += 1;
} else {
count -= 1;
}
if (count == 0) {
candidate = numbers[i+1];
count = 1;
}
}
return candidate;
}
}