169.多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
一、计数法
用HashMap
class Solution {
public int majorityElement(int[] nums) {
HashMap<Integer,Integer> map=new HashMap<Integer,Integer> ();
int m=0;
for(int i=0;i<nums.length;i++){
//记录每个元素出现次数
if(map.containsKey(nums[i])){
map.replace(nums[i],map.get(nums[i])+1);
//当出现次数大于n/2,把这个值记录下来为m
if(map.get(nums[i])>nums.length/2){
m=nums[i];
}
}else{
map.put(nums[i],1);
}
}
//特殊情况当n=1的时候,返回本身
return nums.length==1?nums[0]:m;
}
}
空间复杂度:O(n)。
时间复杂度:O(n)。
记笔记:
hashmap遍历:
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
二、 排序法
数组中有出现次数大于 n/2 的元素,排好序之后的数组中,相同元素总是相邻的。举个例子:
无论是1 1 1 2 3,0 1 1 1 2还是-1 0 1 1 1,数组中间的元素总是“多数元素”。
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);//排序
return nums[nums.length/2];//排序之后,出现在中间的为多数元素
}
}
时间复杂度:O(nlogn)。将数组排序的时间复杂度为 O(nlogn)。
空间复杂度:O(logn)。如果使用语言自带的排序算法,需要使用O(logn) 的栈空间。如果自己编写堆排序,则只需要使用 O(1)的额外空间。
三、 摩尔投票法.Boyer-Moore 算法
候选人(cand_num)初始化为nums[0],票数count初始化为1。
当遇到与cand_num相同的数,则票数count = count + 1,否则票数count = count - 1。当票数count为0时,更换候选人,并将票数count重置为1。
遍历完数组后,cand_num即为最终答案。
为何这行得通呢?
投票法是遇到相同的则票数 + 1,遇到不同的则票数 - 1。
且“多数元素”的个数> ⌊ n/2 ⌋,其余元素的个数总和<= ⌊ n/2 ⌋。
因此“多数元素”的个数 - 其余元素的个数总和 的结果 肯定 >= 1。
这就相当于每个“多数元素”和其他元素 两两相互抵消,抵消到最后肯定还剩余至少1个“多数元素”。
无论数组是1 2 1 2 1,亦或是1 2 2 1 1,总能得到正确的候选人。
class Solution {
public int majorityElement(int[] nums) {
//初始化第一个元素为候选人nums1,初始票数count为1
int nums1=nums[0];
int count=1;
//遍历其余的元素
for(int i=1;i<nums.length;i++){
//如果当前元素和候选人一样,则票数加1
if(nums[i]==nums1){
count++;
}else{ //不一样,票数减1
count--;
}
//遍历过程中,如果count=0,更换当前元素位候选人,票数count重置为1
if(count==0){
nums1=nums[i];
count=1;
}
}
return nums1;
}
}
时间复杂度:O(n)O(n)。Boyer-Moore 算法只对数组进行了一次遍历。
空间复杂度:O(1)O(1)。Boyer-Moore 算法只需要常数级别的额外空间。