Given an array of integers, every element appears twice except for one. Find that single one.
思路:
最经典的方法,利用两个相同的数异或结果为0的性质,则将整个数组进行异或,相同的数俩俩异或,最后得到的就是那个single number,复杂度是O(n)
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for( int i = 0; i < nums.size(); i++ ){
res ^= nums[i];
}
return res;
}
};
Given an array of integers, every element appears three times except for one. Find that single one.
思路:
这题与上一题不同的地方在于,除了single number,其他数字都出现了3次,这样的话,整个异或就无法消去出现3次的数字,那我们有什么其他的办法呢?如果继续按照位来考虑,每一位可能出现的数字只有0或者1,而且如果某一位出现1,那么在这一位,所有数字(除了single num)出现1的次数总数一定是3的倍数,(比如某一位有5个不同数字是1,那么一共1在这一位出现了5*3 = 15次)那我们可以利用这个性质,统计每一位上1出现的总个数,然后总数除以3取它的余数(如果single number在这1位也是1,那么1一共出现16次,16%3 = 1),余数就是single num在这一位的数字。时间复杂度O(32N)
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int count[32] = {0};
int result = 0;
for (int i = 0; i < 32; i++) {
for (int j = 0; j < nums.size(); j++) {
if ((nums[j] >> i) & 1) {
count[i]++;
}
}
result |= ((count[i] % 3) << i);
}
return result;
}
};
思路2:
那么有没有直接是O(N)的算法呢?答案是肯定的。这边使用了bitmask的概念,开始设3个flag,代表数字第一次出现,第二次出现,第三次出现如果出现1次,则one赋值,出现2次时候,one置0,twos赋值,出现3次时候,one,twos,都置0,threes赋值。具体可以参考https://discuss.leetcode.com/topic/2926/accepted-code-with-proper-explaination-does-anyone-have-a-better-idea/2
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ones = 0, twos = 0, threes = 0;
for (int i = 0; i < nums.size(); i++) {
twos |= ones & nums[i];
ones ^= nums[i];
threes = ones & twos;
ones &= ~threes;
twos &= ~threes;
}
return ones;
}
};
Given an array of numbers nums
, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
For example:
Given nums = [1, 2, 1, 3, 2, 5]
, return [3, 5]
.
思路:
如果对所有元素进行异或,那么最后剩下的是两个single number的异或值,那么如何区分这两个single num呢?我们对最后的异或值进行分析,因为两个数字不同,那最后异或值一定不为0,如果某一位出现1表示这一位上,这两个数字是不同的,那我们就可以利用这个性质,通这一位,对整个数组进行分组,分为这一位是0的和这以为是1的,这样,我们就把这两个single number分到了两个数组中,问题就回到了single number1当中了。(via 剑指offer)
代码:
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int res = 0;
for( int i = 0; i < nums.size(); i++ ){
res ^= nums[i];
}
res &= -res;
vector<int> resoult {0,0};
for( int i = 0; i < nums.size(); i++ ){
if( (nums[i] & res) == 0 ){
resoult[0] ^= nums[i];
}
else{
resoult[1] ^= nums[i];
}
}
return resoult;
}
};
这边比较难理解的是res &= -res;加入res = 2则二进制表示为10; -2的二进制表示为1111111111111111111111111111111111111111111111111111111111111110,则最后位与值为2,其他的数同理,最后得到的是从低位向高位的第一位不同的值。