题目描述
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
示例 1:
输入:nums = [2,2,3,2]
输出:3
示例 2:
输入:nums = [0,1,0,1,0,1,99]
输出:99
进阶:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
我的解法
class Solution {
public int singleNumber(int[] nums) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
//用HashMap存储每个元素出现的次数
for(int i=0;i<nums.length;i++){
if (hashtable.containsKey(nums[i])) {
int value = hashtable.get(nums[i]);
hashtable.put(nums[i],++value);
}else{
hashtable.put(nums[i], 1);
}
}
//遍历hashmap。找到出现次数为1的元素
for (Map.Entry<Integer, Integer> entry : hashtable.entrySet()) {
if(entry.getValue()==1)
return entry.getKey();
}
return 0;
}
}
官方基础解法
class Solution {
public int singleNumber(int[] nums) {
Map<Integer, Integer> freq = new HashMap<Integer, Integer>();
for (int num : nums) {
freq.put(num, freq.getOrDefault(num, 0) + 1);
}
int ans = 0;
for (Map.Entry<Integer, Integer> entry : freq.entrySet()) {
int num = entry.getKey(), occ = entry.getValue();
if (occ == 1) {
ans = num;
break;
}
}
return ans;
}
}
Map.getOrDefault(Object key, V defaultValue);
如果在Map中存在key,则返回key所对应的的value。 如果在Map中不存在key,则返回默认值。例如: map.put(num, map.getOrDefault(num, 0) + 1); 表示:
value默认从1开始,每次操作后num对应的value值加1 可以用来统计数字出现的次数
官方进阶解法1
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for (int i = 0; i < 32; ++i) {
int total = 0;
//计算各位上的1的数量
for (int num: nums) {
total += ((num >> i) & 1);
}
//对3取余,与答案或运算
if (total % 3 != 0) {
ans |= (1 << i);
}
}
return ans;
}
}
复杂度分析
时间复杂度:O(n \log C)=32n
空间复杂度:O(1)。
官方进阶解法2
返回值:
以上是对数字的二进制中 “一位” 的分析,而 int 类型的其他 31 位具有相同的运算规则,因此可将以上公式直接套用在 32 位数上。
遍历完所有数字后,各二进制位都处于状态 00 和状态 01 (取决于 “只出现一次的数字” 的各二进制位是 1 还是 0 ),而此两状态是由 one 来记录的(此两状态下 twos 恒为 0 ),因此返回 ones 即可。
复杂度分析:
时间复杂度 O(N) : 其中 N 位数组 nums 的长度;遍历数组占用 O(N) ,每轮中的常数个位运算操作占用O(32×3×2)=O(1) 。
空间复杂度 O(1) : 变量 ones , twos 使用常数大小的额外空间。
class Solution {
public int singleNumber(int[] nums) {
int a = 0, b = 0;
for (int num : nums) {
int aNext = (~a & b & num) | (a & ~b & ~num), bNext = ~a & (b ^ num);
a = aNext;
b = bNext;
}
return b;
}
}