136. Single Number Ⅰ
Description
Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Example 1:
Input: [2,2,1]
Output: 1
Example 2:
Input: [4,1,2,1,2]
Output: 4
思路
- 遍历: O(n2) O ( n 2 )
- 先排序后遍历: O(nlgn) O ( n l g n )
- 利用hashmap:STL用红黑树实现map 搜索的时间复杂度 O(lgn) O ( l g n ) ,遍历的时间复杂度 ,O(n) , O ( n ) 空间复杂度 O(n) O ( n )
- 利用整数在计算机中的二进制bit表示 XOR: O(n) O ( n )
代码
前两种不予以实现。先实现最优方法4:
利用XOR位运算
参考leetcode解题discuss:https://oj.leetcode.com/discuss/6170/my-o-n-solution-using-xor
因为A XOR A = 0,且XOR运算是可交换的,于是,对于实例{2,1,4,5,2,4,1}就会有这样的结果:
(2^1^4^5^2^4^1) => ((2^2)^(1^1)^(4^4)^(5)) => (0^0^0^5) => 5
就把只出现了一次的元素(其余元素均出现两次)给找出来了!
算法复杂度为O(n),且不需要额外空间,代码如下:
//Runtime: 13 ms beats 99.4%
class Solution {
public:
int singleNumber(vector<int>& nums) {
//利用异或的性质
int res=0;
//此处若改成常规循环for(int i=0;i<nums.size();++i)
//则用时14ms beats 85.23%
for(int a:nums){
res = res^a;
}
return res;
}
};
利用hashmap
class Solution {
public:
int singleNumber(vector<int>& nums) {
map<int,int> m;
for(int i=0;i<nums.size();++i){
++m[nums[i]];
}
for(auto it:m){
if(it.second==1){
return it.first;
}
}
return 0;
}
};
137. Single Number Ⅱ
Description
Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Example 1:
Input: [2,2,3,2]
Output: 3
Example 2:
Input: [0,1,0,1,0,1,99]
Output: 99
思路
四种思路与上题相同。但第四种方法需要稍加变化。
代码
位运算
只有利用位运算才能实现0额外空的线性复杂度
这道题是除了一个单独的数字之外,数组中其他的数字都出现了三次,利用位操作 Bit Operation 来解此题。我们可以建立一个 32 位的数字,来统计每一位上 1 出现的个数,我们知道如果某一位上为 1 的话,那么如果该整数出现了三次,对 3 去余为 0,我们把每个数的对应位都加起来对 3 取余,最终剩下来的那个数就是单独的数字。代码如下:
//Runtime: 12 ms, beats 67.45%
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res=0;
for(int i=0;i<32;++i){
int sum=0;
for(int n:nums){
sum += (n >> i) & 1;
}
res |= (sum % 3) << i;
}
return res;
}
};
根据上面解法的思路,我们把数组中数字的每一位累加起来对 3 取余,剩下的结果就是那个单独数组该位上的数字,由于我们累加的过程都要对 3 取余,那么每一位上累加的过程就是 0->1->2->0,换成二进制的表示为 00->01->10->00,那么我们可以写出对应关系:
00 (+) 1 = 01
01 (+) 1 = 10
10 (+) 1 = 00 ( mod 3)
那么我们用 ab 来表示开始的状态,对于加 1 操作后,得到的新状态的 ab 的算法如下:
b = b xor r & ~a;
a = a xor r & ~b;
我们这里的 ab 就是上面的三种状态 00,01,10 的十位和各位,刚开始的时候,a 和 b 都是 0,当此时遇到数字 1 的时候,b 更新为 1,a 更新为 0,就是 01 的状态;再次遇到 1 的时候,b 更新为 0,a 更新为 1,就是 10 的状态;再次遇到 1 的时候,b 更新为 0,a 更新为 0,就是 00 的状态,相当于重置了;最后的结果保存在 b 中。明白了上面的分析过程,就能写出代码如下:
//Runtime: 10 ms, beats 98.76%
class Solution {
public:
int singleNumber(vector<int>& nums) {
int a = 0, b = 0;
for (int i = 0; i < nums.size(); ++i) {
b = (b ^ nums[i]) & ~a;
a = (a ^ nums[i]) & ~b;
}
return b;
}
};
参考博文:http://www.cnblogs.com/grandyang/p/4263927.html
hashmap
//Runtime: 16 ms, beats 20.05%
class Solution {
public:
int singleNumber(vector<int>& nums) {
map<int,int> m;
for(int i=0;i<nums.size();++i){
++m[nums[i]];
}
for(auto it:m){
if(it.second != 3){
return it.first;
}
}
return -1;
}
};
260. Single Number III
Description
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]
.
Note:
- The order of the result is not important. So in the above example,
[5, 3]
is also correct. - Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?
思路
这道题其实是很巧妙的利用了 Single Number 单独的数字的解法,因为那道解法是可以准确的找出只出现了一次的数字,但前提是其他数字必须出现两次才行。而这题有两个数字都只出现了一次,那么我们如果能想办法把原数组分为两个小数组,不相同的两个数字分别在两个小数组中,这样分别调用 Single Number 单独的数字的解法就可以得到答案。
那么如何实现呢?首先我们先把原数组全部异或起来,那么我们会得到一个数字,这个数字是两个不相同的数字异或的结果,我们取出其中任意一位为‘1’的位,为了方便起见,我们用 a &= -a 来取出最右端为‘1’的位,然后和原数组中的数字挨个相与,那么我们要求的两个不同的数字就被分到了两个小组中,分别将两个小组中的数字都异或起来,就可以得到最终结果了,参见代码如下:
代码
//Runtime: 14 ms, beats 86.72%
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int diff = accumulate(nums.begin(), nums.end(), 0, bit_xor<int>());
diff &= -diff;
vector<int> res(2, 0);
for (auto &a : nums) {
if (a & diff) res[0] ^= a;
else res[1] ^= a;
}
return res;
}
};