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

位运算算法实战:从字符唯一性到缺失数字查找

位运算算法实战:从字符唯一性到缺失数字查找。涵盖判断字符唯一性、寻找缺失数字、无符号加法实现、单次出现数字识别及双缺失数字查找等经典场景。通过异或消去特性、位图映射及比特位统计模三等方法,展示如何在不使用额外空间或常规算术运算符的情况下高效解决问题。重点解析代码逻辑背后的数学原理与边界处理,适合希望深入理解底层计算机制的开发者参考。

PentesterX发布于 2026/3/30更新于 2026/4/241 浏览
位运算算法实战:从字符唯一性到缺失数字查找

常见位运算总结

前置知识:常用位运算技巧

在深入具体题目之前,先回顾几个高频使用的位运算技巧,它们往往是解题的关键。

1. 清除最右侧的 1 n & (n - 1) 可以将整数 n 二进制表示中最右侧的 1 变为 0。这个操作常用于统计二进制中 1 的个数(汉明重量)。

class Solution {
public:
    int hammingWeight(int n) {
        int count = 0;
        while (n) {
            n &= (n - 1);
            count++;
        }
        return count;
    }
};

2. 异或运算的性质

  • 任何数与自身异或结果为 0 (a ^ a = 0)。
  • 任何数与 0 异或结果为其本身 (a ^ 0 = a)。
  • 异或满足交换律和结合律。

利用这些性质,可以解决'只出现一次的数字'类问题。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result = 0;
        for (int num : nums) {
            result ^= num;
        }
        return result;
    }
};

033 判断字符是否唯一

题目描述: 实现一个算法,确定一个字符串的所有字符是否全都不同。这里假设字符串只包含小写字母。

解法思路:位图思想

由于题目限制只包含小写字母,总共只有 26 个字符。我们可以用一个整数的二进制位来代表一个字符是否存在。一个 int 类型有 32 位,足以覆盖所有小写字母。

  • 如果某一位是 0,表示该字符未出现过。
  • 如果某一位是 1,表示该字符已出现过。

此外,利用鸽巢原理,如果字符串长度超过 26,必然存在重复字符,可直接返回 false。

算法实现

class Solution {
public:
    bool isUnique(string astr) {
        // 利用鸽巢原理做优化
        if (astr.size() > 26) return false;
        
        int bitMap = 0;
        for (char ch : astr) {
            int i = ch - 'a';
            // 检查第 i 位是否已经是 1
            if ((bitMap >> i) & 1) return false;
            // 将第 i 位设为 1
            bitMap |= (1 << i);
        }
        return true;
    }
};

关键点

实际编码时,注意位移操作的优先级。(bitMap >> i) & 1 用于读取特定位,bitMap |= (1 << i) 用于设置特定位。推导过程中建议自己在纸上画出二进制变化过程,这有助于理解位图映射的本质。


034 丢失的数字

题目描述: 给定一个包含 [0, n] 中 n 个数的数组,找出其中没有出现的那个数。

解法思路:异或消去

数组长度为 n,原本应该包含 0 到 n 共 n+1 个数。现在少了一个。

如果我们把数组中的所有元素,以及 0 到 n 的所有数字全部进行异或运算,根据异或的特性(相同为 0),成对出现的数字都会抵消为 0,最终剩下的就是那个缺失的数字。

算法实现

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int ret = 0;
        // 异或数组中的元素
        for (int x : nums) ret ^= x;
        // 异或 0 到 n 的所有数字
        for (int i = 0; i <= nums.size(); i++) ret ^= i;
        return ret;
    }
};

关键点

这种方法空间复杂度为 O(1),时间复杂度为 O(n)。不需要额外的哈希表或排序,非常高效。核心在于理解'成对抵消'的逻辑。


035 两整数之和

题目描述: 不使用运算符 + 和 -,计算两个整数 a 和 b 的和。

解法思路:模拟加法器

计算机底层加法是通过逻辑门电路实现的,可以分为两步:

  1. 无进位相加:使用异或 ^ 运算。1 ^ 1 = 0, 0 ^ 0 = 0, 1 ^ 0 = 1。
  2. 计算进位:使用按位与 & 运算并左移一位。1 & 1 = 1,进位发生在高位。

循环执行这两个步骤,直到进位为 0,此时 a 即为最终结果。

算法实现

class Solution {
public:
    int getSum(int a, int b) {
        while (b != 0) {
            int x = a ^ b;              // 无进位和
            unsigned int carry = (unsigned int)(a & b) << 1; // 进位
            a = x;
            b = carry;
        }
        return a;
    }
};

关键点

注意进位计算时使用了 unsigned int 强制转换。因为如果 a & b 的结果是负数(最高位为 1),直接左移可能导致未定义行为。转换为无符号数后左移是安全的。虽然面试中可以直接写 return a + b;,但掌握底层原理对理解计算机组成至关重要。


036 只出现一次的数字 II

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

解法思路:比特位计数

既然其他数字都出现了三次,那么对于任意一个比特位,如果我们将所有数字在该位上的值加起来,总和应该是 3 的倍数加上目标数字在该位的值(0 或 1)。

因此,遍历 32 个比特位,统计每一位上 1 出现的次数。如果次数模 3 余 1,说明目标数字在该位上是 1;否则是 0。

算法实现

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for (int i = 0; i < 32; i++) {
            int sum = 0;
            for (int x : nums) {
                if (((x >> i) & 1) == 1) sum++;
            }
            if (sum % 3 == 1) {
                ret |= (1 << i);
            }
        }
        return ret;
    }
};

关键点

此方法适用于'出现 K 次找 1 次'的通用场景。虽然代码嵌套了两层循环,但外层固定为 32,整体时间复杂度仍视为 O(n)。处理负数时需注意补码表示,上述逻辑对补码同样有效。


037 消失的两个数字

题目描述: 给定一个包含 0 到 n 中 n 个数的数组,其中有两个数字消失了,找出这两个数字。

解法思路:组合拳

这道题其实是前面两道题的结合版:

  1. 类似于'丢失的数字',先将数组中的数和 1 到 n+2 区间内的所有数异或在一起。这样得到的结果是两个缺失数字的异或值(记为 tmp)。
  2. 类似于'只出现一次的数字 III',我们需要找到区分这两个缺失数字的某一位。tmp 中为 1 的位,说明这两个缺失数字在这一位上不同。
  3. 根据这一位将原数组和完整序列分为两组,分别异或,即可得到两个缺失数字。

算法实现

class Solution {
public:
    vector<int> missingTwo(vector<int>& nums) {
        int tmp = 0;
        // 1. 异或所有数字
        for (int 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. 分组异或
        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};
    }
};

关键点

关键在于找到区分位 diff。只要找到任意一个不同的比特位,就能将两个目标数分到不同的组里,从而通过异或消除其他干扰项。这种分治思想在位运算题目中非常经典。


结语

位运算不仅是面试中的高频考点,更是理解计算机底层数据处理的基石。掌握这些技巧,不仅能写出更高效的代码,还能在面对复杂问题时找到意想不到的突破口。建议在练习时多尝试自己推导二进制变化过程,加深理解。

目录

  1. 常见位运算总结
  2. 前置知识:常用位运算技巧
  3. 033 判断字符是否唯一
  4. 解法思路:位图思想
  5. 算法实现
  6. 关键点
  7. 034 丢失的数字
  8. 解法思路:异或消去
  9. 算法实现
  10. 关键点
  11. 035 两整数之和
  12. 解法思路:模拟加法器
  13. 算法实现
  14. 关键点
  15. 036 只出现一次的数字 II
  16. 解法思路:比特位计数
  17. 算法实现
  18. 关键点
  19. 037 消失的两个数字
  20. 解法思路:组合拳
  21. 算法实现
  22. 关键点
  23. 结语
  • 💰 8折买阿里云服务器限时8折了解详情
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • 基于 Kiro 与 AIClient-2-API 免费调用 Claude Opus 4.5 实战
  • OpenClaw Dashboard 无法登录:systemd 缺失导致 Gateway 未启动
  • 基于 SpringBoot 的艺术展览网站设计与实现
  • Hugging Face 访问令牌申请指南:以 Meta-Llama-3.1-8B-Instruct 为例
  • 别把 F1 开成老头乐:GitHub Copilot 深度调教与 7 个“上下文工程”秘籍
  • AI Agent 中的 Skills 概念与作用解析
  • Rust Cow 详解:写时复制机制与性能优化
  • C++ 模板深入进阶
  • 哈希表原理详解:从哈希函数到冲突解决的 C++ 实现
  • 通义千问2.5-7B代码生成能力评测:与GitHub Copilot对比
  • AIGC 本地部署硬件配置要求与推荐主机清单
  • 国产 AI 编程助手全景:Claude Code 平替方案与成本差异
  • 双指针专题:复写零问题模拟
  • 字符编码原理与系统乱码问题解析
  • 2026 年 3 月 20 日人工智能产业动态与前沿趋势
  • C++ 精灵库相对运动动画演示:葫芦娃飞向太空
  • FastAPI:Python 高性能 Web 框架核心特性解析
  • AI 绘画报错:CheckpointLoaderSimple 模型缺失解决方案
  • 数据结构:树与堆
  • 无人机视觉任务主流数据集汇总:检测与分割资源整理

相关免费在线工具

  • 加密/解密文本

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