news 2026/8/28 12:44:18

算法日记专题:位运算II( 只出现一次的数字I II III 面试题:消失的两个数字 比特位计数)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法日记专题:位运算II( 只出现一次的数字I II III 面试题:消失的两个数字 比特位计数)

🎬 胖咕噜的稞达鸭:个人主页

🔥 个人专栏: 《数据结构》《C++初阶高阶》
《Linux系统学习》
《算法日记》
⛺️技术的杠杆,撬动整个世界!

🐥位运算常见总结:



本专题的前缀文章:

算法日记专题:位运算I(汉明距离I II 面试题:判断是不是唯一的字符 丢失的数字 两个整数相加)

只出现一次的数字I

力扣链接

算法原理:
将数组中所有元素都异或在一起,除了某个元素只出现一次以外,其余每个元素均出现两次。最终异或的结果就是所求。

classSolution{public:intsingleNumber(vector<int>&nums){intsum=0;for(intnum:nums)sum^=num;returnsum;}};

只出现一次的数字II

链接力扣

算法原理:位运算
把数组中的数字都放在bit中,有32个位,0 和 1 指的是某个数字的二进制表示中的一位(bit)的值。

3n个0 + singel 0; -----取模 0
3n个0 + singel 1; -----取模 1
3n个1 + singel 0; -----取模 0
3n个1 + singel 1; -----取模 1
对于每一位 i:

  1. 统计数组中所有数字在该位为 1 的个数(sum)
  2. 因为除了目标数字外,其他数字都出现 3 次,所以 sum = 3×k + b
    • k 是出现 3 次的数字中该位为 1 的个数
    • b 是目标数字在该位的值(0 或 1)
  3. sum % 3 = b,所以:
    • 如果 b = 0 → 目标数字该位为 0
    • 如果 b = 1 → 目标数字该位为 1,设置 ret 的该位为 1
      这样遍历完 32 位后,ret 就是只出现一次的数字。
classSolution{public:intsingleNumber(vector<int>&nums){intret=0;//用于返回最后的结果for(inti=0;i<32;i++)//修改ret中的值{intsum=0;for(intx:nums)//遍历nums,计算nums中所有数字的第i位的和if(((x>>i)&1)==1)//此时第i位置的数字为1sum++;sum%=3;//所有出现在nums第0位的数字都加起来,再取模3if(sum==1)ret|=(1<<i);//判断如果sum 最后取模等于1,就说明这个数字单独出现过}returnret;}};

只出现一次的数字III

只出现一次的数字力扣链接

解题原理:

  1. 所有数异或:
    一个数组中只有两个数字只出现了一次,其余都出现了两次,先将数组中所有的数字都进行异或,最后剩下的一个数字就是唯一出现一次的这两个数字的异或和;
  2. 分组:找不同;(找出不同的才可以分组:那干脆去找异或和中的最低位置的1)
    先找出这个异或和最低位置的1,定义为diff(一定有1存在)找出这个1所在的编号,
  3. 如果这个编号跟1按位与,最终结果就是1;再跟数组中的其他数字异或,最后可以找出来这个数;
    这个编号跟0按位与,最终结果就是0;再跟数组中的其他数字异或,最后可以找出另外一个数字;
  4. 最后返回这两个数字。
classSolution{public:vector<int>singleNumber(vector<int>&nums){inttmp=0;for(inti:nums)tmp^=i;//tmp中存储异或和unsignedintdiff=(unsignedint)tmp&-(unsignedint)tmp;inta=0,b=0;for(intnum:nums){if(diff&num)a^=num;elseb^=num;}return{a,b};}};

面试题:消失的两个数字

消失的两个数字力扣链接

解法:数组中本身有nums个数字,
这些数字加上消失的两个数字a,b,恰好是1~N中连续的数字区间,
所以nums中数字(缺失数组)+ 这段区间(完整数组) —>构成问题:只出现一次的数字III
关键:其余数字都出现了两次,只有a和b出现了一次,返回a 和 b.
解题:

  1. 可以将所有的数字异或在一起,将结果收集在tmp中,tmp = a^ b;
  2. 找到tmp中比特位为1的那一位(异或的时候相同为0相异为1):
  3. 根据x位的不同,划分为两类异或:
    将这个x位置比特位为1的数字,将其其余的数字都跟1异或在一起;(假设是b类)
    将这个x位置比特位为0的数字,将其其余的数字都跟0异或在一起;(假设是a类)

    注意:这个其余的数字,既要在完整数组中进行异或操作,也要在缺失数组中进行异或。
    其余数字都出现过两次,只有其中一位数字只出现了一次;
classSolution{public:vector<int>missingTwo(vector<int>&nums){inttmp=0;for(inti=1;i<=nums.size()+2;i++)tmp^=i;for(intnum:nums)tmp^=num;//找出ab比特位中不同的那一位intdiff=0;while(1){if(((tmp>>diff)&1)==1)break;elsediff++;}//根据diff的不同,将所有的数字都划分为两类来进行异或inta=0,b=0;for(intnum:nums)if(((num>>diff)&1)==1)b^=num;elsea^=num;for(inti=1;i<=nums.size()+2;i++)if(((i>>diff)&1)==1)b^=i;elsea^=i;return{a,b};}};

方法二:位运算:取最低位次的1

classSolution{public:vector<int>missingTwo(vector<int>&nums){intsum=0;for(inti=1;i<=nums.size()+2;i++)sum^=i;for(intnum:nums)sum^=num;intlowbit=sum&-sum;//取出最低位置的1在哪一位,如果是倒数第二位就是2,倒数第三位就是3,是一个编号inta=0,b=0;for(inti=1;i<=nums.size()+2;i++){if(i&lowbit)a^=i;//判断这个位置的数字和i按位与,如果i是0,按位与的结果是0;elseb^=i;//如果按位与的结果是1,最终要按照lowbit算,取编号}for(intnum:nums){if(num&lowbit)a^=num;elseb^=num;}return{a,b};}};

比特位计数

比特位计数力扣链接

题目解析
对于0 <= i <= n中的每个i,计算其二进制表示中1的个数,返回一个长度为n + 1的数组ans作为答案。
思路:
找出0 <= i <= n中每一个数字二进制表示中总共有几个1,数组中表示的是每一个i位有几个1;将每一个数字放到位图中,每一位为1,sum ++,一个数字放好到位图中之后返回sum。
ret[x]中收集每一个countBit中返回的sum个数,sum用来计数字1.

classSolution{public:vector<int>countBits(intn){vector<int>ret(n+1);//用于返回最终结果的ret有n+1个空间,第n个数字二进制中有几个1也要返回autocountBit=[](intx){intsum=0;for(inti=0;i<32;i++){if((x>>i)&1)sum++;//将x右移动i位,并且按位与1判断它的第i个位置是1还是0,如果是1就sum++}returnsum;//返回这个数字的二进制数有多少个1};//多次调用countBit(x) 函数计算 x 的二进制中 1 的个数for(intx=0;x<=n;x++){ret[x]=countBit(x);//将结果存储在数组 ret 的第 x 个位置}returnret;}};

通过这道题我们可以总结出:(x >> i) & 1的操作适用于以下情景:

  1. 判断n的第i位是0还是1:
if((n>>i)&1)
  1. 统计二进制中1的个数:
intcountBits(intx){intsum=0;for(inti=0;i<32;i++){if((x>>i)&1)sum++;//x不断右移动i个位置,跟1按位与}returnsum;}

示例:

int x = 13; // 二进制:1101
int sum = 0;
int i = 0;
// 检查第0位
if((13 >> 0) & 1) sum++; // (1101 & 1) = 1,sum变为1
// 检查第1位
if((13 >> 1) & 1) sum++; // (0110 & 1) = 0,sum不变
// 检查第2位
if((13 >> 2) & 1) sum++; // (0011 & 1) = 1,sum变为2
// 检查第3位
if((13 >> 3) & 1) sum++; // (0001 & 1) = 1,sum变为3

所以13的二进制表达中有3个1.

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 4:49:29

Pinia 完整使用指南

Pinia 是 Vue 官方推荐的状态管理库&#xff0c;用于跨组件、跨页面共享状态&#xff0c;其功能定位与 Vuex 一致&#xff0c;但具备更简洁的 API 设计、更好的 TypeScript 支持&#xff0c;且移除了 Vuex 中繁琐的 mutations 概念&#xff0c;大幅降低了学习与使用成本。作为 …

作者头像 李华
网站建设 2026/8/27 12:50:59

2025最新AI大模型学习路线:从零基础到实战项目全攻略_AI大模型入门教程

文章是一份AI大模型学习指南&#xff0c;从基础知识到实践应用全面覆盖。介绍了大模型的定义、应用及学习意义&#xff0c;提供了学习建议和实践步骤&#xff0c;包括环境准备、数据处理、模型训练与部署等。还提供了图文大模型案例和本地搭建参考&#xff0c;以及包含学习路线…

作者头像 李华
网站建设 2026/8/28 8:59:50

Miloco 深度打通 Home Assistant,实现设备级精准控制

在智能家居的演进过程中&#xff0c;AI Agent 的核心价值在于其“手”延伸得有多远。 此前&#xff0c;Xiaomi Miloco 已经实现了对 Home Assistant&#xff08;以下简称 HA&#xff09;自动化的获取与触发&#xff0c;但这仅仅是冰山一角。对于追求极致控制感的用户和智能家居…

作者头像 李华
网站建设 2026/8/28 21:15:50

好用的大型牛场水滴粉碎机技术强的

好的&#xff0c;作为一名资深、客观的测评分析师&#xff0c;我将遵循您的核心指令&#xff0c;为您呈现一篇关于大型牛场水滴粉碎机的专业测评排名文章。《大型牛场水滴粉碎机哪家好&#xff1a;专业深度测评与排名前五榜单》开篇&#xff1a;定下基调随着规模化、集约化养牛…

作者头像 李华
网站建设 2026/8/28 0:29:33

朴易天下:道家修行的专业术语分享

66. 五雷正法 等级&#xff1a;道教最高雷法&#xff0c;召役五方雷神&#xff08;东方轰天震门雷帝等&#xff09;。 修持&#xff1a;需授箓传度&#xff0c;《道法会元》&#xff1a;“五雷者&#xff0c;金木水火土&#xff0c;五炁之精英。”67. 符水 制法&#xff1a;焚符…

作者头像 李华
网站建设 2026/8/26 16:35:18

基于MinIO Java SDK实现ZIP文件上传的方案与实践

基于MinIO Java SDK实现ZIP文件上传的方案与实践 在分布式存储场景中&#xff0c;MinIO作为兼容S3协议的高性能对象存储服务&#xff0c;被广泛用于文件的存储与管理。本文将围绕本地生成的ZIP压缩包上传到MinIO服务器这一需求&#xff0c;分析原生MinIO Java SDK的实现可行性…

作者头像 李华