一、题意
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.
二、分析和解答
1、返回出现次数超过 ⌊ n/2 ⌋ 次的数。我的想法:使用HashMap保存每一个数以及该数出现的次数,找到次数最多的那位即可(其实都出现总数的一半了,那肯定是最多的了)。代码如下:
public int majorityElement(int[] nums) {
int max = 0;
int result = -1;
HashMap<Integer,Integer> map = new HashMap();
for(int i=0;i<nums.length;i++){
if(map.containsKey(nums[i]))
map.put(nums[i],map.get(nums[i]) + 1);
else//这里的else容易忘记,导致错误!
map.put(nums[i],1);
}
Set<Integer> set = map.keySet();
for(Integer key : set){
int value = map.get(key);
if(max < value){
max = value;
result = key;
}
}
return result;
}
这里回顾一下HashMap的遍历方法:
(1)得到key的集合,然后根据key从map中得到value,如上面的代码(通过键来获取值);
(2)通过map.values()来获取所有的值的集合,然后进行遍历输出;由于这样无法的到key,还得单独获取,所以在这里不适用;
(3)通过获取键值对的方式,map.entrySet()
Set<Map.Entry<Integer,Integer>> set = map.entrySet();
for(Map.Entry<Integer,Integer> entry : set){
int key = entry.getKey();
int value = entry.getValue();
if(max < value){
max = value;
result = key;
}
}
(4)通过entrySet的遍历器
Set<Map.Entry<Integer,Integer>> set = map.entrySet();
Iterator<Map.Entry<Integer,Integer>> it = set.iterator();
while(it.hasNext()){
Map.Entry<Integer,Integer> entry = it.next();
int key = entry.getKey();
int value = entry.getValue();
if(max < value){
max = value;
result = key;
}
}
2、还可以使用排序。在这里可以复习一下java相关的排序函数
3、还可以使用分治法和位操作来完成。其实这个分治法就是快速排序划分的变形,我开始也想到使用划分操作来获得中间值,但是没想通。
参考《剑指offer》可以知道:成熟的O(n)的算法可以得到数组中任意第k大的数字。
其实我们要得到的就是数组的中间位置的值,而随机快排的划分算法返回的值就是选择pivot那个值在数组中的位置,随机快排的pivot的值的选择是随机的。于是,当随机选中的那个数字所对应的下标正好是n/2,那么就是所求的中位数;若对应的下标小于n/2,那么中位数就应该在它的右边;若对应的下标大于n/2,那么中位数就应该在它的左边。
我写的代码如下(超时了过去了一半的案例):
int paratition(int[] nums,int low,int high){
Random r = new Random();
int index = r.nextInt(high - low + 1) + low;
int pivot = nums[index];
int t = nums[low];
nums[low] = nums[index];
nums[index] = t;
while(low < high){
//while(high < nums.length && nums[high] < pivot)
while(low < high && nums[high] >= pivot)
high--;
nums[low] = nums[high];
//while(low < nums.length && nums[low] > pivot)
while(low < high && nums[low] <= pivot)
low++;
nums[high] = nums[low];
//int t = nums[low];
//nums[low] = nums[high];
//nums[high] = t;
}
nums[low] = pivot;
return low;
}
public int majorityElement(int[] nums) {
int low = 0,high = nums.length -1;
int middle = (low + high) / 2;
int key = paratition(nums,low,high);
while(key != middle){
if(key < middle)
key = paratition(nums,key+1,high);
else
key = paratition(nums,low,key-1);
}
if(key == middle)
return nums[middle];
return nums[middle];
}
没找到有人有这么个写法,时间复杂度(快排的)我还不会分析,这是一个遗留问题!
4、这种方法是基于如果一个数在这个数组中是出现次数最多的,那么在删去一对不同的数后剩下的子数组中,该数也是出现次数最多的。这种算法名为Moore Voting Algorithm。代码为:
public int majorityElement(int[] nums) {
int majority = -1;
int count = 0;
for(int i=0;i<nums.length;i++){
if(count == 0){
majority = nums[i];
}
if(majority == nums[i])
count++;
else
count--;
}
if(count > 0)// 更详细: >= nums.length/2+1
return majority;
return majority;
}
我们遍历这个数组的时候,定义一个count用来计数,这个超过一半的数,它遇到自己就给count加1,遇到不是自己的数,就给count减1,最后会怎样呢,count肯定大于0呐,因为这个数的个数超过一半。好,进一步的,我们先随便找个数当这个老大(个数超过一半),如果它的个数不超过一半,就会在相消中时count为0,那么就把它换掉,最后剩下的那个就是,个数超过一半的那个数了。【这段话是复制的】
初始选第一个元素,依次比对它和其它的元素,若相等则其票数加一,反之则减一,当其票数为0时,更换投票对象为当前的元素,继续执行,最终即可得结果(前提的数组中存在这样的数,否则结果不确定是什么,依赖于元素的摆放顺序)。
参考:http://blog.csdn.net/zdavb/article/details/47837017
https://www.cnblogs.com/tjuloading/p/4614397.html