位运算(判断字符是否唯一)(1)

一.题目

面试题 01.01. 判定字符是否唯一 - 力扣(LeetCode)

二.思路

关于这题有很多方法可以解决,但是我们本章是位运算因此我们只用位运算进行讲解!

2.1 认识位图

位图 是一种非常高效的数据结构,它的核心思想是利用二进制位 来标记某个元素是否存在。与传统的数组不同,数组每个元素通常占用 4 字节 (如 int)或 1 字节 (如 char),而位图只占用 1 个比特位 。也就是说,1 字节可以记录 8 个元素的状态 ,极大地节省了空间。在计算机中,每个比特位只有 01 两种状态,因此我们可以用 0 表示元素未出现,用 1 表示元素已出现。这种紧凑的表示方式在处理大量"存在性"判断问题时非常有效。

2.2 为什么可以使用位图

本题限定字符集为 小写字母 ,一共只有 26 个 。这意味着我们只需要 26 个比特位 就能完整记录每个字符是否出现过。而在 C++ 中,一个 int 类型 恰好占用 32 位 ,足够容纳这 26 个标记。因此,我们完全可以用一个 int 变量 来充当位图,而不必使用数组或哈希表。这样既节省了空间,又能利用位运算进行快速操作。

2.3 本题用的两个位运算公式

在处理位图时,我们需要两个核心操作:检查某一位是否为 1将某一位设置为 1。这两个操作可以通过位运算高效实现:

  • 判断某一位是否为 1

公式: (n >> x) & 1

含义: 将数字 n 的二进制表示向右移动 x 位,使第 x 位移动到最低位,然后与 1 进行按位与运算。如果结果为 1,说明原第 x 位是 1;否则为 0。 用途:当我们要添加一个新字符时,先检查该字符对应的位是否已经为 1,如果是,则说明该字符重复出现,可以直接返回结果。

  • 将某一位修改为 1

公式: n |= (1 << x)

含义: 先将 1 左移 x 位,得到只有第 x 位为 1 的数值,然后与 n 进行按位或运算。由于或运算的特性,n 中其他位保持不变,而第 x 位无论原来是 0 还是 1,都会变成 1。 用途:当一个新字符第一次出现时,我们用它将该字符对应的位标记为已存在 ,即把该位设为 1,这样后续就可以通过第一个公式来检查重复。

三.代码演示

cpp 复制代码
class Solution {
public:
    bool isUnique(string astr)
    {
        int b = 0;
        int n = astr.size();
        //位图使用
        for(int i = 0;i < n;i++)
        {
            //获取元素
            int ch = astr[i] - 'a';

            //判断这个元素是否存在
            if((b >> ch) & 1)
                return false;

            //添加这个元素到位图
            b |= (1 << ch);
        }    
        return true;
    }
};

四.代码讲解

一、初始化位图变量

为了标记字符串中每个字符是否出现过,我们使用一个整型变量 b 来充当位图 。由于题目限定字符为小写字母 ,共26个,而 int 类型有32位,足够容纳所有标记。初始时,b 的所有位都是 0,表示没有任何字符出现过。

二、遍历字符串并操作

接下来,我们遍历字符串中的每一个字符。对于每个字符,执行以下三个步骤:

  1. 计算字符对应的位偏移 :将当前字符 astr[i] 减去字符 'a',得到一个 0 到 25 之间的整数 ch,这个整数就是该字符在位图中对应的比特位位置

  2. 检查该位是否已存在 :使用位运算公式 (b >> ch) & 1 来判断位图中第 ch 位是否为 1

    • 如果结果为 1 ,说明该字符之前已经出现过,即字符串中存在重复字符,此时直接返回 false

    • 如果结果为 0,说明该字符是首次出现,继续下一步。

  3. 将该位标记为已存在 :使用位运算公式 b |= (1 << ch) 将位图中第 ch 位设置为 1。这样,后续再遇到相同字符时,就能通过上一步检查出来。

遍历结束后,如果没有发现任何重复字符,则返回 true,表示字符串中所有字符都是唯一的。

三、关键细节
  • 位图的选择 :因为字符集只有小写字母,所以用一个 int 变量就足够,无需使用数组或哈希表,既节省空间又提高效率。

  • 位运算的巧妙 :两个核心公式 (b >> ch) & 1b |= (1 << ch) 分别实现了查询设置 操作,时间复杂度均为 O(1)

  • 字符映射 :通过 astr[i] - 'a' 将字符映射到 0~25 的索引,确保每个字符对应唯一的比特位。

  • 提前返回 :一旦发现重复,立即返回 false,无需继续遍历,提高效率。

相关推荐
ShineWinsu1 分钟前
对于Linux:内核是如何组织管理IPC资源的解析
linux·服务器·c++·面试·笔试·线程·ipc
少司府22 分钟前
C++进阶:红黑树
开发语言·数据结构·c++·b树·二叉树·红黑树
工业胶粘剂技术30 分钟前
单组分高温环氧结构胶 K-EP280 完整技术参数与工程选型分析
算法·制造
汉克老师38 分钟前
GESP6级C++考试语法知识(五十五、动态规划----背包问题(八、混合背包)
c++·动态规划·dp·背包问题·gesp六级·混合背包问题
特种加菲猫39 分钟前
哈希表的实现
开发语言·c++
玖釉-40 分钟前
nvpro_core2 详解:NVIDIA Vulkan / OpenGL 图形样例背后的现代 C++ 基础库
c++·windows·图形渲染
不会C语言的男孩41 分钟前
C++ Primer 第19章:特殊工具与技术
数据结构·c++
不会C语言的男孩1 小时前
C++ Primer 第18章:用于大型程序的工具
开发语言·c++
星恒随风1 小时前
C++ 类和对象入门(三):拷贝构造、赋值运算符重载和深浅拷贝
开发语言·c++·笔记·学习
Cx330❀1 小时前
【MySQL基础】库与表的全面操纵指南
linux·服务器·网络·数据库·c++·mysql