137. 只出现一次的数字 II - 力扣(LeetCode)
260. 只出现一次的数字 III - 力扣(LeetCode)
三道题目都可以用哈希表来做,这里主要介绍位运算的解法,不多解释。
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
不适用额外空间,我们就要有一个条件反射,就是使用位运算
关于异或:a^a=0 a^0=a
所以我们只需要遍历数组并且对每个元素连续进行异或就能得到答案
class Solution {
public int singleNumber(int[] nums) {
int result=0;
for(int i=0;i<nums.length;i++){
result=result^nums[i];
}
return result;
}
}
给你一个整数数组
nums
,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
我们在上一题中使用异或操作的实质就是将重复数字进行抵消,那么这一题的思路也是一样的。不过异或显然不能将三个相同数字抵消。我们可以统计所有数字的每一位中‘1’出现的次数,将次数模3,就能抵消三个相同数字,最后得到的就是唯一的那个数字。
class Solution {
public int singleNumber(int[] nums) {
int[] cnt = new int[32];
for (int x : nums) {
for (int i = 0; i < 32; i++) {
if (((x >> i) & 1) == 1) {//每个数字都是32位,将数字右移i位与1做与运算,就是看右移后的最后一位是不是1,即原32位中第i位是不是1
cnt[i]++;
}
}
}
int ans = 0;
for (int i = 0; i < 32; i++) {
if (cnt[i] % 3 == 1) {//cnt[i]%3==1就是唯一元素的第i位都是1
ans += (1 << i);//恢复每一位1的权值,得到原数字
}
}
return ans;
}
}
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
如果我们按照题目一的解法,直接进行异或运算,得到的是两个出现一次的数字的异或结果,但是如果我们能想办法把两个数字分开分别进行异或就可以解。我们观察二者异或的结果,必定不为0,肯定有一位是1。我们根据该位是否为1来将nums分为两组进行异或运算
class Solution {
public int[] singleNumber(int[] nums) {
int diff = 0;
for (int n : nums) {
diff ^= n;
}
diff = Integer.highestOneBit(diff);//Integer.highestOneBit 方法,它可以保留某个数的最高位的 1,其它位全部置 0。也可以 diff &= -diff;即先取反加一,相与后取最低为的1
int[] result = { 0, 0 };
for (int n : nums) {
//当前位是 0 的组, 然后组内异或
if ((diff & n) == 0) {
result[0] ^= n;
//当前位是 1 的组
} else {
result[1] ^= n;
}
}
return result;
}