跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

算法实战:消失的两个数字(位运算解法)

给定一个包含 n-2 个不同整数的数组,取值范围 1 到 n+2,要求找出缺失的两个数字。利用异或运算特性,将所有数组元素与完整序列进行异或,结果即为两缺失数的异或值。通过提取该结果中任意一个为 1 的二进制位,将数字划分为两组,每组内部再次异或即可分离出两个缺失数。该方法无需额外存储空间,时间复杂度 O(n),空间复杂度 O(1),适合处理大规模数据场景。

ApiHolic发布于 2026/3/22更新于 2026/5/1010 浏览
算法实战:消失的两个数字(位运算解法)

题目描述

给定一个包含 n-2 个不同整数的数组,这些整数取自范围 [1, n]。请找出缺失的那两个数字。

示例: 输入:nums = [1] 输出:[2, 3] 解释:n=3,数组中只有 1,缺失的是 2 和 3。

输入:nums = [2, 3] 输出:[1, 4] 解释:n=4,数组中有 2 和 3,缺失的是 1 和 4。

解题思路

这道题是经典位运算问题的变种。核心思想利用异或(XOR)运算的特性:

  1. 相同为 0,不同为 1:任何数与自身异或结果为 0,与 0 异或结果为其本身。
  2. 交换律与结合律:异或运算的顺序不影响最终结果。

如果我们把数组中的所有元素与 1 到 n+2 的所有整数进行异或,那么出现两次的数字会互相抵消变为 0,最终剩下的结果就是那两个缺失数字的异或值(记为 ret)。

假设缺失的两个数为 A 和 B,则 ret = A ^ B。因为 A != B,所以 ret 一定不为 0,这意味着在二进制表示中至少有一位是 1。我们可以找到这一位,将原数组和 1 到 n+2 的数字根据该位是 0 还是 1 分成两组。A 和 B 必然分属不同的组,而相同的数字依然会在同一组内成对出现。分别对两组进行异或,即可分别得到 A 和 B。

代码实现

这里提供两种基于异或分组的具体写法。第一种通过循环查找差异位,第二种利用位运算技巧直接获取最低有效位。

方案一:通用位拆分

这种方法直观地寻找 ret 中任意一个为 1 的比特位,然后进行分组。

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int ret = 0;
        // 第一步:计算所有数字的异或和
        for (auto x : nums) ret ^= x;
        for (int i = 1; i <= nums.size() + 2; i++) ret ^= i;

        // 第二步:找出 ret 中任意一个为 1 的位
        int differ = 0;
        while (!((ret >> differ) & 1)) {
            differ++;
        }

        // 第三步:根据该位将数字分为两组分别异或
        int a = 0, b = 0;
        for (auto x : nums) {
             ((x >> differ) & ) b ^= x;
             a ^= x;
        }
         ( i = ; i <= nums.() + ; i++) {
             ((i >> differ) & ) b ^= i;
             a ^= i;
        }

         {a, b};
    }
};
if
1
else
for
int
1
size
2
if
1
else
return
方案二:最低有效位优化

利用 x & (-x) 可以快速提取出二进制中最右边的 1,这比循环查找更高效且代码更简洁。

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int temp = 0;
        // 计算总异或值
        for (auto& x : nums) temp ^= x;
        for (int i = 1; i <= nums.size() + 2; i++) temp ^= i;

        // 提取最低位的 1,作为区分标准
        int ls = temp & (-temp);

        int a = 0, b = 0;
        // 分组异或
        for (auto& x : nums) {
            if (x & ls) a ^= x;
            else b ^= x;
        }
        for (int i = 1; i <= nums.size() + 2; i++) {
            if (i & ls) a ^= i;
            else b ^= i;
        }

        return {a, b};
    }
};

复杂度分析

  • 时间复杂度:O(n)。我们需要遍历数组两次(一次计算总异或,一次分组),以及遍历 1 到 n+2 的范围,整体线性增长。
  • 空间复杂度:O(1)。仅使用了几个整型变量存储中间结果,没有使用额外的数据结构。

这种解法在处理大规模数据时非常高效,避免了使用哈希表或布尔数组带来的额外内存开销。在实际面试中,能够识别出异或特性并推导出分组策略,通常是考察重点。

目录

  1. 题目描述
  2. 解题思路
  3. 代码实现
  4. 方案一:通用位拆分
  5. 方案二:最低有效位优化
  6. 复杂度分析
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • 飞牛 NAS 开启 SSH 连接方法及笔记本息屏操作
  • Java IO 流进阶:缓冲流、序列化与打印流
  • 安路 FPGA 开发工具 TD 全流程使用指南
  • AI 产品架构设计:从 0 到 1 搭建信息架构与核心业务流程
  • 大厂 AI 岗位核心技能指南:前端、后端与算法实战
  • 基于 Claude Code 的 AI 内容创作自动化工作流实践
  • MGit 安卓 Git 客户端使用教程:手机端代码管理指南
  • YOLO12 WebUI 入门:使用最新目标检测模型
  • Git LFS 跨平台安装与配置实战指南
  • Linux System V 共享内存:原理、实操与避坑指南
  • 开源知识库 RAGFlow 从部署到实战操作详解
  • JNI 本质解析:Android Framework 下的 Java-Native 衔接机制
  • Spring Cloud Tencent 适配 Spring Boot 3 及 Java 17 升级指南
  • 16 届蓝桥杯 Java 组省赛真题详解:思路与代码实现
  • 前端开发:善用组件库,拒绝重复造轮子
  • 基于 YOLO11 的无人机航拍小目标检测系统实战
  • 数据分析职业发展路径与核心技能体系解析
  • SLAM Toolbox 机器人定位与建图实践
  • 无人机路径规划技术:A*算法与GPS定位实现
  • Visual C++ 运行库完整方案与 DLL 依赖管理

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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