给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99
根据上一道题目的经验,我们很明确的知道不能用数数字的办法去解。考虑位运算的办法,找相关的性质。
这个题其实就是求,在其他数都出现 k 次的数组中有一个数只出现一次,求出这个数。
而上面那个 k 次的是有通用解法的。
使用一个 32 维的数组,用这个 32 维的数组存储:
[第 31 位 1 的总数, 第 30 位 1 的个数,…, 第 1 位 1 的个数]
假如第 0 位 1 的个数是 k 的倍数,那么要求的这个数在该位一定是 0 ;
若不是 k 的倍数,那么要求的这个数在该位一定是 1。
因为假如说数组中的某些数在该位置是 1,那么因为这个数要么出现 k 次,那么出现 1 次。
这样我们就可以找出只出现一次那个数的二进制表示形式。二进制如何转化为 10 进制呢?
假如,按照上面的规则,最招找到的二进制为:
A = [0, 0, 0, 0, 0, …, 1]
因为异或操作是:相同为 0,不同为 1。
那么久可以依次用 1, 2, 4, 8 … 和依次每一位异或,即可得到最终答案。
第二部分可能不好理解,可以手动模拟下。
class Solution {
public int singleNumber(int[] nums) {
// 有多少个相同的数字
int N = 3;
// [高位 1 的个数,...,低位 1 的个数]
int[] bitNum = new int[32];
for (int i = 0; i < nums.length; i++) {
int compare = 1;
int num = nums[i];
for (int j = bitNum.length - 1; j >= 0; j--) {
if ((compare&num) != 0) {
bitNum[j]++;
}
compare = compare << 1;
}
}
int compare = 1;
int res = 0;
for(int i = bitNum.length - 1; i >= 0; i--) {
if(bitNum[i] % N != 0) {
res = res ^ compare;
}
}
return res;
}
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.