LeetCode 关于位运算的几道题

零、异或的概念

性质

两个数字异或的结果a^b是将 ab 的二进制每一位进行运算,得出的数字。

运算的逻辑是相同为1,不同为0。

规律

  1. 任何数本身异或则为 0

  2. 任何数0 异或本身

  3. 异或满足交换律。 即 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 = b2b1 ^ 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;
}

猜你喜欢

转载自blog.csdn.net/qq_32963855/article/details/107926662