136. 只出现一次的数字
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
解题思路
位运算:
从头到尾对每个数进行一遍^
运算最后得到的那个数就是出现一次的数,因为相同的数^
后的结果为0
int singleNumber(vector<int>& nums) {
int ans = 0;
for(int i = 0; i < nums.size(); i++)
{
ans ^= nums[i];
}
return ans;
}
137. 只出现一次的数字 II
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99
解题思路
位运算:
为了区分出现一次的数字和出现三次的数字,使用两个位掩码:seen_once 和 seen_twice。
仅当 seen_twice 未变时,改变 seen_once。
仅当 seen_once 未变时,改变seen_twice。
位掩码 seen_once 仅保留出现一次的数字,不保留出现三次的数字。
int singleNumber(vector<int>& nums) {
int twice = 0, once = 0;
for(auto x:nums)
{
once = ~twice&(once^x);
twice = ~once&(twice^x);
}
return once;
}
260. 只出现一次的数字 III
题目描述
位运算-设置两个掩码
本文将使用两个按位技巧:
使用异或运算可以帮助我们消除出现两次的数字;我们计算 bitmask ^= x,则 bitmask 留下的就是出现奇数次的位。
x & (-x) 是保留位中最右边 1 ,且将其余的 1 设位 0 的方法。
算法:
首先计算 bitmask ^= x,则 bitmask 不会保留出现两次数字的值,因为相同数字的异或值为 0。
但是 bitmask 会保留只出现一次的两个数字(x 和 y)之间的差异。
我们可以直接从 bitmask 中提取 x 和 y 吗?不能,但是我们可以用 bitmask 作为标记来分离 x 和 y。
我们通过 bitmask & (-bitmask) 保留 bitmask 最右边的 1,这个 1 要么来自 x,要么来自 y。
当我们找到了 x,那么 y = bitmask^x。
vector<int> singleNumber(vector<int>& nums) {
int bitcheck = 0;
for(int x : nums) bitcheck ^= x;
// 剔除最右边的 1 把它当做特征位
int flag = bitcheck & (-bitcheck); // -bitcheck => (~bitcheck + 1)
int x = 0;
// 将全部有特征位的数相与 剩余最后的 x 就是其中一个只出现一次的元素
for(int num : nums) if(num & flag) x ^= num;
return {x,bitcheck ^ x};
}
注: 本文题解引用自LeetCode官方题解