零、异或的概念
性质
两个数字异或的结果a^b
是将 a
和 b
的二进制每一位进行运算,得出的数字。
运算的逻辑是相同为1,不同为0。
规律
-
任何数
和本身
异或则为0
-
任何数
和0
异或是本身
-
异或满足交换律。 即
a ^ b ^ c
,等价于a ^ c ^ b
LeetCode136、只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
设初始值xor_val = 0
则 xor_val ^ nums[0] ^ nums[1]...
由题目性质:
1个元素出现一次;设为a
,
其他元素出现两次。设为 b 1 b_1 b1、 b 2 b_2 b2、 c 1 c_1 c1、 c 2 c_2 c2、 d 1 d_1 d1、 d 2 d_2 d2……
其中 b 1 = b 2 b_1 = b_2 b1=b2,
c 1 = c 2 c_1 = c_2 c1=c2,
…
由异或性质:
xor_val ^ nums[0] ^ nums[1]...
可以写成 xor_val ^ a ^ b1 ^ b2...
【交换律】
b1 = b2
故 b1 ^ b2 = 0
故式子可写成0^a = a
int singleNumber(int* nums, int numsSize){
int xor_val = 0;
for(int i = 0 ; i < numsSize; i++){
xor_val ^= nums[i];
}
return xor_val;
}
LeetCode137、只出现一次的数字 II
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99
上面的方法不适用了。
考虑使用32位常数空间记录每个数字的二进制位上出现1的个数。
若最后不能被3整除,则该位为答案的二进制位之一。
int singleNumber(int* nums, int numsSize){
int cnt[32] = {
0};
long temp;
for(int i = 0 ; i < numsSize; i++){
temp = 1;
for(int j = 0 ; j < 32; j++){
if(nums[i] & temp) cnt[j]++;
temp <<= 1;
}
}
int rst = 0;
temp = 1;
for(int i = 0; i < 32; i++){
if(cnt[i] % 3) rst += temp;
temp <<= 1;
}
return rst;
}
剑指 Offer 56 - I. 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
int* singleNumbers(int* nums, int numsSize, int* returnSize){
int xor_val = 0;
for(int i = 0; i < numsSize; i++)
xor_val ^= nums[i]; // 思路同1,得到最后的xor_val为不同的两个数字的异或值
int idx = 1;// xor_val可知是这两个不同的数字的“所有不同二进制位”的集合
// 我们希望通过左移的方式,得到一位不同的二进制值就好
while((xor_val & idx) == 0){
idx <<= 1;//
}
int rst1, rst2;
rst1 = rst2 = 0;
for(int i = 0 ; i < numsSize; i++){
if(nums[i] & idx) rst1 ^= nums[i];
else rst2 ^= nums[i];
}
//printf("%d %d %d %d",xor_val, idx, rst1, rst2);
int* ans = (int*)malloc(sizeof(int)*2);
ans[0] = rst1, ans[1] = rst2;
*returnSize = 2;
return ans;
}