题目描述; 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法一
HashMap方法
依次遍历数组,然后统计数组元素的个数,最后,根据key,找到value==1的数
java实现
class Solution{
public int singleNumber(int [] nums)
HashMap <Integer,Integer> hashmap=new HashMap<>();
for(int num:nums)
hashMap.put(num,hashmap.getOrDefault(num,0)+1);
for(int k:hashmap.keySet())
if(hashmap.get(k)==1)
return k;
return -1;
}
}
方法二:
HashSet
建议先看HashMap详解
将输入数组存储到 HashSet,然后使用 HashSet 中数字和的三倍与数组之和比较。
3×(a+b+c)−(a+a+a+b+b+b+c)=2c
class Solution{
Set< Long> set=new HashSet<>();
long sumSet=0,sumArray=0;
for(int n:nums){
sumArray+=n;
set.add((long)n);
}
for(Long s1:set)
sumSet+=s;
return (int)((3*sumSet-sumArray)/2);
}
}
方法三:
位运算
位运算符号
- ~表示位运算NOT
- &表示位运算AND
- 异或表示位运算符号XOR
XOR
可以用来检测出现奇次的位:1,3,5,,
0与任何数XOR都是本身
相同的数异或XOR等于0
所以只有某个位置出现了奇数次,该位的掩码不为0
因此,可以检测出现一次的位或者出现三次的位,但是需要区分
为了区分出现一次和出现三次的数字,使用两个位掩码;
once和twice
- 仅当twice 未变时,改变once。
- 仅当once 未变时,改变wice。
位掩码once保留出现一次的数字,不保留出现三次的数字
class Solution {
public int singleNumber(int[] nums) {
int Once = 0, Twice = 0;
for (int num : nums) {
// 第一次出现
// 把num添加到once中
// 不把num添加到twice中因为num已经出现在once中了
// 第二次出现
// 从once中移除num
// num添加到twice中
// 第三次出现
// num不添加到once中,因为num已经出现在twice中了
//从twice中移除num
Once = ~Twice & (Once ^ num);
Twice = ~Once & (Twice ^ num);
}
return Once;
}
}