手撕力扣之位运算:两整数之和、只出现一次的数字(I、 II)、丢失的数字、汉明距离、数字的补数、二进制中1的个数、Pow(x, n)、数组中数字出现的次数、数组中数字出现的次数 II、求1+2+…+n

力扣371. 两整数之和
不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和。

二进制的加法无外乎就以下几种情况,
1+1 = 0 (有进位)
1+0 = 1 (无进位)
0+0 = 0 (无进位)
0+1 = 1 (无进位)
仔细一看,在不考虑进位的情况下,这个不就是二进制的异或操作嘛。所以,我们就可以把加法分成无进位的异或结果,a^b 与保存的进位相加,循环直到没有进位为止,就可以得到结果了。
再分析二进制加法中进位怎么能保存,因为只有 1+1的时候会产生进位,这不就是与操作嘛,a&b 但是进位需要在更高的一位,所以我们就左移一位嘛就搞定了,
所以,进位就可以这样保存
c = (a&b)<<1;
这样就可以用 a = (a^b) ^ c 得到一轮结果 ,但是有可能还会有进位,所以需要将这个放在循环里面就可以了。

class Solution {
public:
    int getSum(int a, int b) {
    while (b)
    {
        auto carry = ((unsigned int ) (a & b))<<1 ; // 记录a+b的进位,直到进位为0是退出
        a = a^b;   //结果相加
        b = carry;  //循环
    }
    return a;
    }
};
作者:zi-lun
链接:https://leetcode-cn.com/problems/sum-of-two-integers/solution/cshi-xian-xiang-jie-by-zi-lun/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
1.交换律:a ^ b ^ c <=> a ^ c ^ b
2.任何数于0异或为任何数 0 ^ n => n
3.相同的数异或为0: n ^ n => 0

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res=0;
        for(int i=0;i<nums.size();i++)
        {
            res^=nums[i];
        }
        return res;
    }
};

力扣137. 只出现一次的数字 II
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
统计所有数字中每个位中1出现的总数,那么对于某个位,1出现的次数一定是3的倍数+1或0,那么对这个数%3得到的结果就是目的数字在该位上的值。
【位运算,可以推广到在多个重复n次的数字中找到出现一次的数字】

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0;
        for(int i = 0;i < 32;++i){
            int sum = 0;
            for(int j = 0;j < nums.size();++j){
                sum += (nums[j] >> i) & 1;
            }
            res ^= (sum % 3) << i;
        }
        return res;
    }
};

作者:yzh
链接:https://leetcode-cn.com/problems/single-number-ii/solution/zhi-chu-xian-yi-ci-de-shu-zi-wei-yun-suan-ke-yi-tu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣268. 丢失的数字
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

int missingNumber(vector<int>& nums) {
    int res = nums.size();
    for (int i = 0; i < nums.size(); ++i){
        res ^= nums[i];
        res ^= i;
    }
    return res;
}

力扣461. 汉明距离
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。

class Solution {
public:
    int hammingDistance(int x, int y) {
        //计算异或的值
        int n = x ^ y;
        //计算
        int counter = 0;
        //将每一个元素左移然后进行计算
        while ( n > 0)
        {
            counter += n & 1;
            n >>= 1;
        }
        return counter;
    }
};

作者:matlab
链接:https://leetcode-cn.com/problems/hamming-distance/solution/cji-bai-shuang-bai-fen-bai-by-matlab/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣476. 数字的补数
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
思路:统计num有多少位,与c异或即可

int temp = num, c = 0;
        while(temp > 0){
            temp >>= 1;
            c =  (c << 1) + 1;
        }
        return num ^ c;

力扣剑指 Offer 15. 二进制中1的个数
方法一:

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while(n != 0)
        {
            if(n & 1) count ++;
            n >>= 1;
        }
        return count;
    }
};

作者:superkakayong
链接:https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/solution/fei-zi-jie-ti-ku-jian-15-jian-dan-er-jin-zhi-zhong/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

方法二:
利用 n & (n - 1) 来消除n最右边的1,然后如果n还是不等于0的话,让count++,同时继续消除n最右边的1。
这种方法比上一种更快,因为这种方法是n有多少个1,就遍历多少次,而上一种是要从头遍历到尾,每一个元素都要判断一遍。

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while(n != 0)
        {
            count ++;
            n = n & (n - 1);
        }
        return count;
    }
};

作者:superkakayong
链接:https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/solution/fei-zi-jie-ti-ku-jian-15-jian-dan-er-jin-zhi-zhong/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣050. Pow(x, n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数。
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
在这里插入图片描述

class Solution {
public:
    double myPow(double x, int n) {
        if(x == 1 || n == 0) return 1;
        double ans = 1;
        long num = n;
        if(n < 0){
            num = -num;
            x = 1/x;
        }
        while(num){
            if(num & 1) ans *= x;
            x *= x;
            num >>= 1;
        }
        return ans;
    }
};

作者:yizhe-shi
链接:https://leetcode-cn.com/problems/powx-n/solution/c-cheng-fa-kuai-su-mi-by-yizhe-shi-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣剑指 Offer 56 - I. 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
思路:
相同的数异或为0,不同的异或为1。0和任何数异或等于这个数本身。
所以,数组里面所有数异或 = 目标两个数异或 。 由于这两个数不同,所以异或结果必然不为0。
假设数组异或的二进制结果为10010,那么说明这两个数从右向左数第2位是不同的
那么可以根据数组里面所有数的第二位为0或者1将数组划分为2个。
这样做可以将目标数必然分散在不同的数组中,而且相同的数必然落在同一个数组中。
这两个数组里面的数各自进行异或,得到的结果就是答案


class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int ret=0;
        //全部做异或,让两只单身狗异或结果出来
        for(int num:nums)
            ret ^= num;
        int div=1;

        //找到分别单身狗的过滤规则
        while ((div & ret) == 0)
            div <<= 1;
        int a = 0, b = 0;

        //根据过滤规则,扔到两个旅游团,情侣一定会到同一个旅游团,而单身狗一定单身。
        for (int n : nums)
            if (div & n)
                a ^= n;
            else
                b ^= n;
        
        return vector<int>{a, b};
    }
};


作者:blood-5
链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/he-xin-si-lu-dan-shen-gou-dai-zhao-yi-dui-yi-dui-q/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣剑指 Offer 56 - II. 数组中数字出现的次数 II
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
思路:
值得注意的是:如果某个数字出现3次,那么这个3个数字的和肯定能被3整除,则其对应二进制位的每一位的和也能被3整除
统计数组中每个数字的二进制中每一位的和,判断该和是否能被3整除。
若可以,则只出现一次的数字的二进制数中那一位为0,否则为1

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        for(int i = 0; i < 32; ++i){
            int cnt = 0;
            for(int n : nums){
                // n & 1 << i 的值大于0即为真
                if(n & (1 << i)) cnt++;
            }
            // 构造只出现一次的那个数字,采用异或的方法生成二进制中的每一位
            if(cnt % 3 == 1) ans ^= (1 << i);
        }
        return ans;
    }
};

作者:jarvis1890
链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/solution/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-ha-xi-bi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

剑指 Offer 64. 求1+2+…+n
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
以逻辑运算符 && 为例,对于 A && B 这个表达式,如果 A 表达式返回 False ,那么 A && B 已经确定为False ,此时不会去执行表达式 B。
利用这一特性,我们可以将判断是否为递归的出口看作 A && B 表达式中的 A 部分,递归的主体函数看作 B 部分。如果不是递归出口,则返回True,并继续执行表达式 B 的部分,否则递归结束。当然,你也可以用逻辑运算符 || 给出类似的实现,这里我们只提供结合逻辑运算符 && 的递归实现。

class Solution {
public:
    int sumNums(int n) {
        n && (n += sumNums(n-1));
        return n;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/qiu-12n-lcof/solution/qiu-12n-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值