位运算算法

常见位运算总结

1、基础位运算

&(按位与):有0就是0

|(按位或):有1就是1

^(按位异或):相同为0,相异为1或者无进位相加

2、给定一个数n,确定二进制第x位是1还是0

(n>>x)&1

3、将一个数n的二进制第x位修改为1

n|=1

4、将一个数n的二进制第x为修改为0

n&=(~(1<<x))

5、提取一个数n二进制最右边的1

注:-n=~n+1

n&-n

-n将n先取反,然后+1

6、删除一个数n二进制最右边的1

n&(n-1)

-1就可以把最右边的1借位过去从而变成0,该位置后面全是0,现在借位过去就会全变成1

1、判定字符是否唯一

https://leetcode.cn/problems/is-unique-lcci/description/

算法原理:

只有26个字母,所以只需要位图26位比特位就能存

按位或将字母存到对应位置,比如a就存在位图第一位,b在第二位

通过按位与操作判断当前位置

代码

cpp 复制代码
class Solution {
public:
    bool isUnique(string astr) {
        // 位图
        // 只有26个字母,把astr进行标记
        int str = 0;
        for (auto s : astr) {
            int now =1<<(s - 'a');
            if (now & str) // 当前字母已经存在
            {
                return false;
            }

            str |= now;
        }

        return true;
    }
};

2、丢失的数字

268. 丢失的数字 - 力扣(LeetCode)

算法原理

异或运算:相同数字进行异或运算,结果是0

代码

cpp 复制代码
class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int ret=0;
        int size=nums.size();
        for(int i=0;i<size;i++)
        {
            ret^=i^nums[i];
        }

        return ret^size;
    }
};

3、两整数之和

371. 两整数之和 - 力扣(LeetCode)

算法原理:

1、a^b 是 无进位和的位置

2、(a&b)<<1 是 进位的位置

一直循环 上述操作,直到最后(a&b)<<1为0,也就是没有进位了,那么a^b就是最后结果

画图理解

cpp 复制代码
13+28=41
  32 16 8 4 2 1
a+b 
        a:  0 0 1 1 0 1
        b:  0 1 1 1 0 0
            ------------------------------------------
a^b:        0 1 0 0 0 1 --(a)
(a&b)<<1:   0 1 1 0 0 0 --(b)
            ------------------------------------------
a^b:        0 0 1 0 0 1 --(a)
(a&b)<<1:   1 0 0 0 0 0 --(b)
            ------------------------------------------
a^b:        1 0 1 0 0 1 ☆ →41
(a&b)<<1:   0 0 0 0 0 0

代码

cpp 复制代码
class Solution {
public:
    int getSum(int a, int b) {
        //a^b 不进位相加
        //(a&b)<<1 进位的位置

        if(b==0)
            return a;

        while(b!=0)
        {
            int tmpa=a^b;
            int tmpb=(a&b)<<1;
            a=tmpa;
            b=tmpb;
        }

        return a;
        
    }
};

4、只出现一次的数字 II

137. 只出现一次的数字 II - 力扣(LeetCode)

算法原理:

把所有数的二进制位分开相加,因为有三个相同的数,也就是每位上都有3n个0或者1,再加上出现一次的1或者0,会出现如下规律

cpp 复制代码
(3n个0 +0 )%3 =0
(3n个1 +0 )%3 =0
(3n个0 +1 )%3 =1
(3n个1 +1 )%3 =1

进行%3操作之后,只有出现一次的数在那个位上为1最后的结果才会为1

代码

cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        //最大数为32位,把所有数二进制位分开相加,然后%3,多出来的位置一定是1
        int ret=0;
        for(int i=0;i<32;i++)
        {
        int count=0;

            for(auto e: nums)
            {
                //将所有数进行按位与运算
                count+=(e>>i)&1;
            }

            ret|=(count%3)<<i;
        }

        return ret;

    }
};

5、只出现一次的数字 III

260. 只出现一次的数字 III - 力扣(LeetCode)

算法原理:

1、所有数进行异或操作,最后异或的结果就是两个不重复的数的异或结果x

2、通过x&(-x)取最后一个1的位置

为什么要取这个位置?

异或相同为0,相异为1,最后一个位置上为1,表示一个数当前位置为0,另一个当前位置为1

3、通过判断所有元素在x最后一个1的位置是否为1

是1的异或到type1

不是1的异或到type2

为什么这样就可以将两个不重复数分开?

因为相同数在这个位置要么都在type1,要么都在type2,都会异或为0

代码

cpp 复制代码
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
    int xorsum=0;
    for(auto num:nums)
    {
        xorsum^=num;
    }

    //INT_MIN取反会溢出
    int last=(xorsum==INT_MIN?xorsum:xorsum&(-xorsum));//取出二进制最低位的1

    int type1=0,type2=0;//将nums中那个位置上为0放在type1中,为1的放在type2中
    for(auto num:nums)//两个元素不同,所以那个位置上面一个是0,一个是1,这样异或之后最终type1,type2就是两个不同的数
    {
        if(num&last)
        {
            type1^=num;
        }
        else
        {
            type2^=num;
        }
    }
    return {type1,type2};

    }

};

6、消失的两个数字

面试题 17.19. 消失的两个数字 - 力扣(LeetCode)

算法原理:

第三题丢失的数字+第五题只出现一次的数字 |||

1、相同数字异或为0,找到两个小时数字异或之后的结果

2、然后使用第五题的算法原理,就可以将两个数分开

代码

cpp 复制代码
class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        //找到最后一位
        int sum=0;
        int size=nums.size();
        for(int i=0;i<size;i++)
        {
            sum^=i^nums[i];
        }

        sum^=size;
        sum^=size+1;
        sum^=size+2;
        int last=sum&(-sum);

        int type1=0,type2=0;
        //将nums中的数分别存放到type1,type2
        //后面相同异或为0
        for(auto e:nums)
        {
            if(e&last)
                type1^=e;
            else
                type2^=e;
        }


        for(int i=1;i<=size+2;i++)
        {
            if(i&last)
                type1^=i;
            else
                type2^=i;
        }

        return {type1,type2};
    }
};
相关推荐
不穿格子的程序员39 分钟前
从零开始刷算法——双指针-三数之和&接雨水
算法·双指针
无限进步_1 小时前
C语言数组元素删除算法详解:从基础实现到性能优化
c语言·开发语言·windows·git·算法·github·visual studio
松涛和鸣2 小时前
16、C 语言高级指针与结构体
linux·c语言·开发语言·数据结构·git·算法
Booksort2 小时前
【LeetCode】算法技巧专题(持续更新)
算法·leetcode·职场和发展
OJAC1112 小时前
2026高校毕业生1270万!但这些学生却被名企用高薪“提前预定”!
算法
Controller-Inversion2 小时前
岛屿问题(dfs典型问题求解)
java·算法·深度优先
小白程序员成长日记2 小时前
力扣每日一题 2025.11.28
算法·leetcode·职场和发展
Swift社区2 小时前
LeetCode 435 - 无重叠区间
算法·leetcode·职场和发展
sin_hielo2 小时前
leetcode 1018
算法·leetcode