难度简单1204收藏分享切换为英文接收动态反馈
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋
的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3] 输出:3
示例 2:
输入:[2,2,1,1,1,2,2] 输出:2
进阶:
- 尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
常规解法是用HashMap来计数,时间复杂度、空间复杂度都是O(n)。题目要求空间复杂度O(1),我想了半个小时才想到可以用位运算。
一个基础知识是一个Integer数,它其实是有31个bit位,每个位置可能是0或1。那么题目说答案出现次数超过数组长度length的一半,也即该数字对应的bit位上为1也会出现数组长度length的一半。
可以1 << 0, 1<< 1, 1<<2…… 循环,和数组每个数求与运算,结果大于0的话就计数,当计数超过一半说明最终答案在该bit位一定是1,把每个循环的结果求或,就是最终答案。
都是正数的话没有问题,如果有负数,可以去除负号用同样的思路。但注意Integer.MIN_VALUE去除负号就越界了会出问题,因此对Integer.MIN_VALUE要单独处理,这里我提及错误了一次。
class Solution {
public int majorityElement(int[] nums) {
int targetCount = nums.length / 2;
int answer = 0;
int temp;
int count;
for (int i = 0; i < 33; ++i) {
temp = 1 << i;
count = 0;
for (int num : nums) {
if (num > 0 && (temp & num) > 0) {
++count;
if (count > targetCount) {
answer |= temp;
break;
}
}
}
}
if (answer > 0) {
return answer; //找到了答案,且答案是一个正数;
}
//到这里说明答案是一个负数;
//[-2147483648] 去掉负号的话会超过int大小,需要转long来计算,因此这里单独处理;
count = 0;
for (int num : nums) {
if (num == Integer.MIN_VALUE) {
++count;
}
}
if (count > targetCount) {
return Integer.MIN_VALUE;
}
//可以开始去掉负号来处理了,且过滤掉Integer.MIN_VALUE
answer = 0;
temp = 0;
count = 0;
for (int i = 0; i < 32; ++i) {
temp = 1 << i;
count = 0;
for (int num : nums) {
if (num > 0 || num == Integer.MIN_VALUE) {
continue;
}
if ((temp & (-num)) > 0) {
++count;
if (count > targetCount) {
answer |= temp;
break;
}
}
}
}
return -answer;
}
}