229. 求众数 II
难度 中等
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋
次的元素。
示例 1:
输入:[3,2,3]
输出:[3]
示例 2:
输入:nums = [1]
输出:[1]
示例 3:
输入:[1,1,1,3,3,2,2,2]
输出:[1,2]
提示:
1 <= nums.length <= 5 * 104
-109 <= nums[i] <= 109
**进阶:**尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。
题解1 : hash 时间复杂度为 O(n) 空间复杂度为 O(n) hash空间
class Solution { public List<Integer> majorityElement(int[] nums) { //法 1 hashmap存放数字对应的次数 List<Integer> res = new ArrayList<Integer>(); Map<Integer,Integer> map = new HashMap<Integer,Integer>(); for(int i : nums){ if(map.containsKey(i)){ map.put(i,map.get(i)+1); }else{ map.put(i,1); } } map.forEach((key,value) -> { if(value>nums.length/3){ res.add(key); } }); return res; }
题解2 : 排序 计数 时间复杂度nlogn 空间复杂度O1
//法2 排序 进行计数 List<Integer> res = new ArrayList<Integer>(); Arrays.sort(nums); int x=1; //记录出现的次数 for(int i=1;i<nums.length;i++){ if(nums[i]==nums[i-1]){ x++; }else{ if(x>nums.length/3) res.add(nums[i-1]); x=1; } } if(x>nums.length/3){ res.add(nums[nums.length-1]); } return res;
题解三 : 摩尔投票法
基本思路 这个题要找大于
length/3
个数的数 , 所以最多只能有两个 , 所以我们就创建两个候选人变量element1
和element2
变量 用来存放 票数最多的两个人 以及分别对应的票数vote1
和vote2
一开始进去 票数都为0(发现票数为0了就换人) , 所以候选人1就是第一个元素 , 并且它的票数加一 , 第二个候选人就是第二个不同的元素 , 票数+1 ,继续遍历的过程中 遇到与候选人一样的元素时并且票数大于0时,它的票数加一 最后遍历出来的一定是俩个票数最多的
完了开始计票 重新遍历 找出各自的总数然后再判断是否大于了三分之一总数
class Solution { public List<Integer> majorityElement(int[] nums) { int element1 = 0; int element2 = 0; int vote1 = 0; int vote2 = 0; for (int num : nums) { if (vote1 > 0 && num == element1) { //如果该元素为第一个元素,则计数加1 vote1++; } else if (vote2 > 0 && num == element2) { //如果该元素为第二个元素,则计数加1 vote2++; } else if (vote1 == 0) { // 选择第一个元素 element1 = num; vote1++; } else if (vote2 == 0) { // 选择第二个元素 element2 = num; vote2++; } else { //如果三个元素均不相同,则相互抵消1次 vote1--; vote2--; } } //找出人了 开始计票 int cnt1 = 0; int cnt2 = 0; for (int num : nums) { if (vote1 > 0 && num == element1) { cnt1++; } if (vote2 > 0 && num == element2) { cnt2++; } } // 检测元素出现的次数是否满足要求 List<Integer> ans = new ArrayList<>(); if (vote1 > 0 && cnt1 > nums.length / 3) { ans.add(element1); } if (vote2 > 0 && cnt2 > nums.length / 3) { ans.add(element2); } return ans; } }
上面的是两个候选人的情况
下面的是一个候选人的情况
剑指offer 52.数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
假设数组非空,并且一定存在满足条件的数字。
思考题:
- 假设要求只能使用 O(n)的时间和额外 O(1)的空间,该怎么做呢?
样例
输入:[1,2,1,1,3]
输出:1
题解 : 票数严格大于一半时,只能有一个候选人
创建一个count用来记录票数
创建一个val用来存放符合条件的候选人
遍历的时候如果count等于0 就更新当前的候选人 票数加一
count不等于0时 , 再进行判断当前的值是否等于val 等于就count++ 否则就count–
class Solution {
public int moreThanHalfNum_Solution(int[] nums) {
//遍历一次 不能使用额外的空间
//摩尔投票法
int val = 0; //用于存放候选人
int count = 0; //记录当前的票数
for(int i = 0 ; i<nums.length;i++){
if(count==0){
val = nums[i];
count++;
}else{
if(nums[i]==val)
count++;
else
count--;
}
}
return val;
}
}