跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

算法实战:位运算解决两数之和、唯一数字与缺失数字

通过三个经典位运算题目,展示利用异或和按位计数解决整数求和、寻找单一元素及查找缺失数字问题的方法。重点在于理解无进位加法原理、比特位统计模 3 技巧以及分组异或策略,代码采用 C++ 实现,注重空间复杂度优化。

奶糖兔发布于 2026/3/26更新于 2026/5/2219 浏览
算法实战:位运算解决两数之和、唯一数字与缺失数字

算法实战:位运算解决两数之和、唯一数字与缺失数字

在算法面试中,位运算往往能带来意想不到的空间和时间复杂度优化。今天我们来深入探讨三道经典题目,看看如何利用异或、按位与和比特位计数来解决整数求和、寻找单一元素以及查找缺失数字的问题。

35. 两个整数之和

题目描述

不使用运算符 + 和 -,计算两整数 a、b 之和。

解题思路

这道题的核心在于理解计算机底层是如何做加法的。我们可以将加法拆解为两个部分:

  1. 无进位加法:通过异或运算 ^ 实现。例如 1 ^ 1 = 0, 1 ^ 0 = 1,这正好对应了二进制加法中不考虑进位的结果。
  2. 进位计算:通过按位与 & 获取需要进位的位置,然后左移一位 << 1 才是真正需要加到高位上的值。

只要进位不为 0,就需要重复上述过程,直到没有进位为止。

代码实现

class Solution {
public:
    int getSum(int a, int b) {
        // 当进位 b 不为 0 时,继续循环
        while (b != 0) {
            // 无进位相加的结果
            int sumWithoutCarry = a ^ b;
            // 计算进位位置并左移
            int carry = (unsigned int)(a & b) << 1;
            
            a = sumWithoutCarry;
            b = carry;
        }
        return a;
    }
};

注意:在 C++ 中,对有符号整数进行右移或左移可能涉及未定义行为,这里为了安全起见,计算进位时建议强制转换为无符号类型处理,或者确保逻辑正确。


36. 只出现一次的数字 II

题目描述

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

解题思路

既然其他数字都出现了三次,那么对于每一个二进制位来说,所有数字在该位上为 1 的总次数一定是 3 的倍数(如果该位属于重复数字)或者是 3 的倍数加 1(如果该位属于目标数字)。

因此,我们可以统计所有数字在每一位上 1 出现的总次数,然后对 3 取余。如果余数为 1,说明目标数字在这一位上是 1;否则是 0。通过遍历 32 个比特位,即可还原出目标数字。

代码实现

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        // 遍历整数的 32 个比特位
        for (int i = 0; i < 32; i++) {
            int sum = 0;
            // 统计当前位上 1 的个数
            for (int x : nums) {
                sum += ((x >> i) & 1);
            }
            // 如果余数为 1,说明目标数字该位为 1
            if (sum % 3 == 1) {
                ret |= (1 << i);
            }
        }
        return ret;
    }
};

37. 消失的两个数字

题目描述

给定一个包含从 0 到 n 的所有整数,但缺少了两个数字的数组,找出这两个缺失的数字。

解题思路

这道题可以看作是'丢失的数字'和'只出现一次的数字 III'的结合体。核心思路依然是利用异或运算的特性:相同的数异或为 0。

  1. 首先将数组中的所有数字与 1 到 n+2 区间内的所有数字进行异或。由于除了两个缺失数字外,其他数字都出现了两次(一次在数组,一次在区间),它们会互相抵消。
  2. 最终得到的结果 ret 就是两个缺失数字的异或值 a ^ b。
  3. 因为 a 和 b 不同,ret 中至少有一位是 1。找到这个最右侧的 1,根据这一位将数字分为两组。
  4. 分别对这两组进行异或,就能得到 a 和 b。

代码实现

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int ret = 0;
        int a = 0;
        int b = 0;
        
        // 第一步:异或所有数组元素和区间元素,得到 a ^ b
        for (int num : nums) {
            ret ^= num;
        }
        for (int i = 1; i <= nums.size() + 2; i++) {
            ret ^= i;
        }
        
        // 第二步:找到 ret 中最右侧为 1 的位
        int diffBit = 0;
        while (((ret >> diffBit) & 1) == 0) {
            diffBit++;
        }
        
        // 第三步:根据该位分组异或
        for (int num : nums) {
            if ((num >> diffBit) & 1) {
                a ^= num;
            } else {
                b ^= num;
            }
        }
        for (int i = 1; i <= nums.size() + 2; i++) {
            if ((i >> diffBit) & 1) {
                a ^= i;
            } else {
                b ^= i;
            }
        }
        
        return {a, b};
    }
};

通过以上三个例子,我们可以看到位运算在处理整数问题时的高效性。无论是避免进位的加法、统计比特位分布,还是利用异或消除重复项,掌握这些技巧都能让代码更简洁、性能更优。在实际开发中,遇到相关场景不妨多想想位运算的可能性。

目录

  1. 算法实战:位运算解决两数之和、唯一数字与缺失数字
  2. 35. 两个整数之和
  3. 题目描述
  4. 解题思路
  5. 代码实现
  6. 36. 只出现一次的数字 II
  7. 题目描述
  8. 解题思路
  9. 代码实现
  10. 37. 消失的两个数字
  11. 题目描述
  12. 解题思路
  13. 代码实现
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 顺丰发布物流垂直领域大模型“丰语”:覆盖 20 余个业务场景
  • HarmonyOS6 底部导航栏组件 rc_concave_tabbar 使用指南
  • 借助 AI 高效生成测试用例的实操指南
  • GitHub 学生开发者认证全流程及常见问题排查
  • Java 核心面试题与参考答案整理
  • GitHub 多模态大模型项目复现流程
  • Z-Image-Turbo 生成写实图像技术指南
  • SQL 性能优化:连接条件下推技术原理与实践
  • Claude Agent Skills 入门与实战:面向 Web 全栈开发者
  • 大模型微调的核心三要素:算法、数据与算力
  • Cursor, Kiro 与 Google Antigravity:AI 智能体如何重塑开发工作流
  • Spring MVC 中@ControllerAdvice 注解的用法与原理
  • 自学网络安全技术:核心基础与入门路径
  • 使用 Ollama、Open WebUI 和 Docker 本地部署可视化 AI 大语言模型
  • 昇腾 NPU 部署 Llama 2 模型的性能测试与优化实践
  • Awesome GitHub Copilot 定制化功能与资源汇总
  • Elasticsearch 核心概念与 Java 客户端实战
  • Docker 部署 OpenClaw:智谱 AI 本地执行引擎集成指南
  • OpenClaw Mac 环境部署与使用指南
  • Ubuntu 环境下 llama.cpp 编译与性能调优实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online