概述
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
限制:
1 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof
1:我的题解:排序
看到这个题,我想了一会,嗯,然后我笑了 ,这tm排个序,中间的数肯定是出现超过一半的数字啊。。笑着笑着我就哭了,做了这么久的题,沃特么就只想到一个排序,这是要被面试官说等通知的节奏呀,起码排序得自己写吧。。。。。。
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
}
我们来分析一下Arrays.sort();
源码就不贴了,有点长,应该是个快排吧,好像可以指定区间排序样
2:哈希表
class Solution {
public int majorityElement(int[] nums) {
if(nums.length==1)
{
return nums[0];
}
Map<Integer,Integer>map=new HashMap<>();
for(int i=0;i<nums.length;i++)
{
if(map.containsKey(nums[i]))
{
int count=map.get(nums[i]);//先获得当前nums[i]的出现次数
map.put(nums[i],count+1);//把当前nums[i]的出现次数加1
if(count+1>nums.length/2)//计数超过一半,返回当前 nums[i]
{
return nums[i];
}
}
else
{
map.put(nums[i],1);//第一次出现,存入nums[i],出现次数记为1
}
}
return -1;
}
}
参考大佬的Map解法
class Solution{
public int majorityElement(int[] nums) {
Map<Integer, Integer> counts = new HashMap<>();
int length = nums.length;
for (int i = 0; i < length; i++) {
int count = counts.getOrDefault(nums[i], 0) + 1;
//如果某个数字出现的个数已经超过数组的一半,自己返回
if (count > length / 2)
return nums[i];
counts.put(nums[i], count);
}
return -1;
}
}
3:位运算
在java中int类型是32位的,我们只需要判断所有数字在某一位1的个数大于数组长度的一半,那么这个众数在这个位置肯定就是1,我们需要遍历32次,确定这个众数每个位置是0还是1即可。
作者:sdwwld
链接:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/solution/pai-xu-mapwei-yun-suan-mo-er-tou-piao-fa-l47t/
class Solution{
public int majorityElement(int[] nums) {
int major = 0;
int length = nums.length;
//在java中int类型是32位,我们遍历每一位
for (int i = 0, mask = 1; i < 32; i++, mask <<= 1) {
//bitCounts表示所有数字在当前位置1的个数。比如当i=0
//的时候,我们可以认为他表示的是所有数字在二进制位
//中最右边1的总数。
int bitCounts = 0;
for (int j = 0; j < length; j++) {
//判断数字nums[j]的第i(i从0开始)个位置是否为1,
//如果是1,bitCounts就加1
if ((nums[j] & mask) != 0)
bitCounts++;
//如果bitCounts大于数组的一半,那么这个众数在
//这个位置肯定是1,然后通过 major |= mask运算
//把这个位置变为1,后面不需要再判断了,直接终止
//内层循环
if (bitCounts > length / 2) {
major |= mask;
break;
}
}
}
return major;
}
}
4:随机数法
这个程序不能处理没有超过数组长度一半的数字的情况,需要改进,可以把while循环次数改一下嘛,改成数组长度的3倍?就不会因为找不到而死循环了
class Solution {
int majorityElement(int[] nums) {
//每一轮随机选择一个数字,统计出现次数,因为目标出现频率大于二分之一,所以效率较高
Random r = new Random();
while(true)
{
int candidate = nums[r.nextInt(nums.length)];
int count = 0;
for(int i=0;i<nums.length;i++)
{
if(nums[i] == candidate)
++count;
}
if(count > nums.length/2)
return candidate;
}
}
}
5:摩尔投票法
参考:剑指 Offer 39. 数组中出现次数超过一半的数字(摩尔投票法,清晰图解)
摩尔投票法,投我++,不投–,超过一半以上的人投我,那我稳赢哇
核心理念为 票数正负抵消 。此方法时间和空间复杂度分别为 O(N)和 O(1) ,为本题的最佳解法。
我们思考一下,有可能两个都不是众数的数字被消除掉了,因为其中一个被当成了临时众数,比如[1,2,3,3,3],这样更加增加了众数的存活机会
还有可能就是一个众数消除一个非众数。比如[2,1,3,1,4,1,5,1,1,1,1,1,1];
而且最后总会出现一个x,它之后票数和不会再为0,使得票数和大于0;
class Solution {
public int majorityElement(int[] nums) {
int x = 0, votes = 0;
for(int num : nums){
if(votes == 0) x = num;
votes += num == x ? 1 : -1;
}
return x;
}
}
class Solution {
public int majorityElement(int[] nums) {
int x = 0, votes = 0, count = 0;
for(int num : nums){
if(votes == 0) x = num;
votes += num == x ? 1 : -1;
}
// 验证 x 是否为众数
for(int num : nums)
if(num == x) count++;
return count > nums.length / 2 ? x : 0; // 当无众数时返回 0
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/solution/mian-shi-ti-39-shu-zu-zhong-chu-xian-ci-shu-chao-3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总结
HashMap的getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。
新的知识点:摩尔投票法
最后
以上就是搞怪菠萝为你收集整理的剑指 Offer 39. 数组中出现次数超过一半的数字的全部内容,希望文章能够帮你解决剑指 Offer 39. 数组中出现次数超过一半的数字所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复