如果数组中多一半的数都是同一个,则称之为主要元素。给定一个整数数组,找到它的主要元素。若没有,返回-1。
说明:
你有办法在时间复杂度为 O(N),空间复杂度为 O(1) 内完成吗?
示例1
输入:[1,2,5,9,5,9,5,5,5]
输出:5
示例2
输入:[3,2]
输出:-1
示例3
输入:[2,2,1,1,1,2,2]
输出:2
解题思路:
思路1:
数组问题,并涉及到统计,首先想到的是用空间换时间,使用hashmap来统计,但是题目有要求空间复杂度O(1),所以舍弃该方法。
思路2:
对于一个有序数组,如果数组里面存在主要元素,那么这个数组的中间位置肯定是我们要找的元素,按照这个思路,我们先找中间数,然后验证中间数的个数是否占数组多半即可。
时间复杂度O(n),空间复杂度O(1), 写法如下:
class Solution
{
public int majorityElement(int[] nums)
{
Arrays.sort(nums);
int middle = nums[nums.length/2];
int count = 0;
for(int item : nums)
{
if(item == middle && ++count > nums.length/2)
{
return middle;
}
}
return -1;
}
}
运算结果,执行用时:3 ms,内存消耗:43 MB
思路3:
摩尔投票法 ,简而言之就是两个帮派一对一对砍,哪个帮派有人活下来,哪个帮派就最大。
时间复杂度O(n),空间复杂度O(1), 写法如下:
public int majorityElement(int[] nums) {
int len = nums.length;
int count = 1;
int target = nums[0];
for(int i=1;i<len;i++)
{
if(target == nums[i]) //元素相同,帮派人数+1
{
count++;
}else //人数-1,或者新建门派
{
if(count == 0)
{
target = nums[i];
count++;
}else
{
count--;
}
}
}
//检验最终存活下来的元素是否占据多半数组
int targetCount = 0;
for(int item : nums)
{
if(item == target && ++targetCount > nums.length/2)
{
return target;
}
}
return -1;
}
运算结果,执行用时:1 ms,内存消耗:43 MB
综上,由于数组排序比较耗时,所以推荐思路3:摩尔投票法。