[Leetcode] Single Number I | Single Number II
2014-07-19 15:42
323 查看
题目一: Given an array of integers, every element appears twice except
for one. Find that single one.
要求:O(n)时间复杂度,不使用额外空间。
一个数组中其他元素都出现两次,只有一个出现一次,要找到那个出现一次的。因为是需要线性复杂度,就不能用两重循环,又因为不能用额外空间,所以不能用hash,参考了网上的境地算法,都是用位操作实现的。所以这是一个考察位操作功底的题目。
先介绍异或操作,即两个数相同取0,不同则取1;性质:任何一位二进制数同
1 异或都是取反,任何一位二进制数同 0 异或都保持不变。这条性质最直观的应用就是不用额外变量交换两个数。
void exchange(int &a, int &b)
还有个性质是a ^b ^c
= a ^ (b ^ c)
= (a ^ b) ^ c,就是说1^2^3^4^4^3^2=2^2^3^3^4^4^1=1,这就知道怎么解决上面的问题了。
题目二:Given an array of integers, every element appears three times
except for one. Find that single one.
要求:O(n)时间复杂度,不使用额外空间。
这次是其他数都出现了三次,只有一个出现一次,找到这个数。上面的方法就不能用了,但思路还是位操作,利用三个变量ones,
twos , threes分别保存各个二进制位上
1 出现一次、两次、三次的分布情况,如代thress=0100,这表明第三位出现过三次1。我们用与或操作记录某位上出现的1,用与操作记录1再次出现的情况。 最后只需返回变量ones就行了。码如下:
还在网上发现了一种通用解法,处理其他数据出现k次。 int 数据共有32位,可以用32变量存储 这 N 个元素中各个二进制位上 1 出现的次数,最后在进行模k操作,如果为1,那说明这一位是要找元素二进制表示中为 1 的那一位。代码如下:
int singleNumber(int A[], int n) {
int bitnum[32]={0};
int res=0;
for(int i=0; i<32; i++){
for(int j=0; j<n; j++){
bitnum[i]+=(A[j]>>i)&1;
}
res|=(bitnum[i]%3)<<i;
}
return res;
}
继续扩展:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:如果能够把原数组分为两个子数组。在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现一次的数字了。
我们还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。因为其他数字都出现了两次,在异或中全部抵消掉了。由于这两个数字肯定不一样,那么这个异或结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有一位为1。我们在结果数字中找到第一个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0。现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。因此到此为止,所有的问题我们都已经解决。
unsigned int FindFirstBitIs1(int num)
{
int indexBit = 0;
while (((num & 1) == 0) && (indexBit < 32))
{
num = num >> 1;
++ indexBit;
}
return indexBit;
}
for one. Find that single one.
要求:O(n)时间复杂度,不使用额外空间。
一个数组中其他元素都出现两次,只有一个出现一次,要找到那个出现一次的。因为是需要线性复杂度,就不能用两重循环,又因为不能用额外空间,所以不能用hash,参考了网上的境地算法,都是用位操作实现的。所以这是一个考察位操作功底的题目。
先介绍异或操作,即两个数相同取0,不同则取1;性质:任何一位二进制数同
1 异或都是取反,任何一位二进制数同 0 异或都保持不变。这条性质最直观的应用就是不用额外变量交换两个数。
void exchange(int &a, int &b)
{ b=a^b; //b'每位的0和1 表示a,b对应位相同和不同 a=a^b; //a^0得到相同的,a^1得到b的那位 b=b^a; //同样b'^a(b)会得到a }
还有个性质是a ^b ^c
= a ^ (b ^ c)
= (a ^ b) ^ c,就是说1^2^3^4^4^3^2=2^2^3^3^4^4^1=1,这就知道怎么解决上面的问题了。
int singleNumber(int A[], int n) { // Note: The Solution object is instantiated only once and is reused by each test case. if(A == NULL ){ return 0; } int result = A[0]; for(int i = 1; i < n; i++){ result = result ^ A[i]; } return result; }
题目二:Given an array of integers, every element appears three times
except for one. Find that single one.
要求:O(n)时间复杂度,不使用额外空间。
这次是其他数都出现了三次,只有一个出现一次,找到这个数。上面的方法就不能用了,但思路还是位操作,利用三个变量ones,
twos , threes分别保存各个二进制位上
1 出现一次、两次、三次的分布情况,如代thress=0100,这表明第三位出现过三次1。我们用与或操作记录某位上出现的1,用与操作记录1再次出现的情况。 最后只需返回变量ones就行了。码如下:
int singleNumber(int A[], int n) { int ones = 0, twos = 0, threes = 0; for(int i = 0; i < n; i++) { threes = twos & A[i]; //1已经出现两次并且再次出现 twos = twos | ones & A[i]; //1出现两次,ones & A[i]=1的表示 那位还是1 ones = ones | A[i]; //1出现一次, ones | A[i]=1 表示那位上出现了1 twos = twos & ~threes; //当某一位出现三次后,我们就从出现两次中消除该位 ones = ones & ~threes; //当某一位出现三次后,我们就从出现一次中消除该位 } return ones; //twos, threes最终都为0.ones是只出现一次的数 }
还在网上发现了一种通用解法,处理其他数据出现k次。 int 数据共有32位,可以用32变量存储 这 N 个元素中各个二进制位上 1 出现的次数,最后在进行模k操作,如果为1,那说明这一位是要找元素二进制表示中为 1 的那一位。代码如下:
int singleNumber(int A[], int n) {
int bitnum[32]={0};
int res=0;
for(int i=0; i<32; i++){
for(int j=0; j<n; j++){
bitnum[i]+=(A[j]>>i)&1;
}
res|=(bitnum[i]%3)<<i;
}
return res;
}
继续扩展:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:如果能够把原数组分为两个子数组。在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现一次的数字了。
我们还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。因为其他数字都出现了两次,在异或中全部抵消掉了。由于这两个数字肯定不一样,那么这个异或结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有一位为1。我们在结果数字中找到第一个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0。现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。因此到此为止,所有的问题我们都已经解决。
unsigned int FindFirstBitIs1(int num)
{
int indexBit = 0;
while (((num & 1) == 0) && (indexBit < 32))
{
num = num >> 1;
++ indexBit;
}
return indexBit;
}
bool IsBit1(int num, unsigned int indexBit) { num = num >> indexBit; return (num & 1); }
void FindNumsAppearOnce(int data[], int length, int &num1, int &num2) { if (length < 2) return; // get num1 ^ num2 int resultExclusiveOR = 0; for (int i = 0; i < length; ++ i) resultExclusiveOR ^= data[i]; // get index of the first bit, which is 1 in resultExclusiveOR unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR); num1 = num2 = 0; for (int j = 0; j < length; ++ j) { // divide the numbers in data into two groups, // the indexOf1 bit of numbers in the first group is 1, // while in the second group is 0 if(IsBit1(data[j], indexOf1)) num1 ^= data[j]; else num2 ^= data[j]; } }
相关文章推荐
- leetcode single-number-ii
- (复习)[LeetCode]Single Number II
- Leetcode Single Number II
- Leetcode Single Number II
- leetcode(137)数组之Single Number II
- Leetcode Single Number II (面试题推荐)
- Leetcode之SingleNumber I/II/III
- 【leetcode刷题笔记】Single Number II
- 【leetcode】Single Number II
- 【leetcode】Single Number & Single Number II
- LeetCode之Single Number II
- [LeetCode] Single Number II
- leetcode single number I II III [python]
- Single Number II @LeetCode
- Single Number II -- leetcode
- LeetCode Single Number, Single Number II
- leetcode136:single number I&II 及拓展
- leetcode Single Number I II III
- leetcode - Single Number II
- LeetCode:Single Number II