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

面试题解析:消失的两个数字(位运算解法)

LeetCode 面试题 17.19 消失的两个数字可通过位运算高效解决。核心思路是将数组元素与完整区间 [1, n+2] 全部异或,得到两个缺失数的异或值。通过提取该值的最低有效位区分两个数,分组再次异或即可还原。此方法空间复杂度为 O(1),无需额外哈希表,是面试中考察位运算技巧的经典案例。

Stephaine Walsh发布于 2026/3/28更新于 2026/9/861 浏览
面试题解析:消失的两个数字(位运算解法)

面试题:消失的两个数字

题目描述

给定一个包含从 1 到 n+2 的整数数组,其中恰好有两个数字缺失。请找出这两个缺失的数字。

解题思路

这道题是经典位运算问题的组合变体。核心在于利用异或(XOR)运算的特性:

  • 任何数与自身异或结果为 0。
  • 任何数与 0 异或结果为其本身。
  • 异或运算满足交换律和结合律。

如果我们把数组中的所有元素,以及区间 [1, n+2] 中的所有数字全部进行异或,那么出现两次的数字都会抵消为 0,最终剩下的结果就是那两个缺失数字的异或值(记为 temp = a ^ b)。

既然 a != b,那么 temp 一定不为 0,这意味着在二进制表示中至少有一位是 1。我们可以找到这个差异位,根据这一位的不同将原数组和区间数分为两组。每一组中都只包含一个缺失数字(其余数字均成对出现),分别对两组进行异或即可得到 a 和 b。

C++ 实现

这里提供两种常见的实现方式,本质逻辑一致,区别在于寻找差异位的方法略有不同。

方法一:提取最右边的 1

利用 x & (-x) 可以快速提取出二进制中最右侧的 1,这是补码运算的特性。

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int temp = 0;
        // 1. 异或所有数组元素
        for (auto& x : nums) temp ^= x;
        // 2. 异或所有区间 [1, n+2] 的数字
        for (int i = 1; i <= nums.size() + 2; i++) temp ^= i;
        
        // 此时 temp = a ^ b,且至少有一位为 1
        // 提取最右边的 1 作为分组依据
        int ls = temp & (-temp);
        
        int a = 0, b = 0;
        // 3. 根据 ls 位分组异或
        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};
    }
};
方法二:循环查找差异位

如果不熟悉位运算技巧,也可以通过循环移位找到第一个不同的比特位。

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        // 1. 计算两个缺失数的异或值
        int tmp = 0;
        for (auto x : nums) tmp ^= x;
        for (int i = 1; i <= nums.size() + 2; i++) tmp ^= i;
        
        // 2. 找出 tmp 中任意一个为 1 的位(例如最低位)
        int diff = 0;
        while (!((tmp >> diff) & 1)) diff++;
        
        // 3. 根据 diff 位将数字分为两类并分别异或
        int a = 0, b = 0;
        for (int x : nums) {
            if ((x >> diff) & 1) b ^= x;
            else a ^= x;
        }
        for (int i = 1; i <= nums.size() + 2; i++) {
            if ((i >> diff) & 1) b ^= i;
            else a ^= i;
        }
        return {a, b};
    }
};

总结

这两种写法的时间复杂度均为 O(n),空间复杂度为 O(1)。在实际面试中,方法一更体现对位运算底层特性的掌握,代码更简洁;方法二逻辑更直观,易于理解。无论哪种,关键在于理解如何通过异或消除重复项,并利用差异位将问题分解为两个子问题。

目录

  1. 面试题:消失的两个数字
  2. 题目描述
  3. 解题思路
  4. C++ 实现
  5. 方法一:提取最右边的 1
  6. 方法二:循环查找差异位
  7. 总结

更多推荐文章

查看全部
  • Fooocus 部署实践:本地手动配置与云端一键启用对比
  • 通义万相 2.1 技术解析:多模态生成能力与应用前景
  • C++ 哈希扩展:位图与布隆过滤器的原理与实现
  • OpenClaw 集成飞书机器人实战指南
  • AI 绘画在商业设计中的应用与案例分析
  • Web 自动化测试入门:从概念到百度搜索实战
  • 巅峰对决:Codex Multi-Agent vs Claude Agent Teams,谁才是最强 AI 编程团队?
  • 2025 AI 产业全景深度解析与未来趋势洞察
  • 自然语言处理在金融领域的应用与实战
  • 大模型与机器学习学习路线及核心书籍推荐
  • Moments 使用 Docker 本地部署与远程访问配置
  • OpenClaw 飞书机器人权限配置与安全指南
  • AI 终端生态重构与视觉感知驱动的实体交互实践
  • Haversine 距离算法详解
  • Windows 11 下利用 llama.cpp 测试 Qwen3.5 量化模型
  • C++ 多态核心原理与虚函数表详解
  • TrendRadar 本地部署指南:构建个人 AI 热点情报系统
  • 从零开始使用 Isaac Lab 训练机器人行走
  • Python 数据分析基础:NumPy 数组创建与操作详解
  • Llama Factory 模型评估:如何科学衡量微调后的模型性能

相关免费在线工具

  • 加密/解密文本

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