5.1 位运算专题:LeetCode 面试题 01.01. 判定字符是否唯一

1. 题目链接

LeetCode 面试题 01.01. 判定字符是否唯一


2. 题目描述

实现一个算法,确定一个字符串的所有字符是否全部唯一(即没有重复字符)。要求如下:

  • 不使用额外的数据结构(如哈希表)
  • 字符串仅包含小写字母 a-z

示例

  • 输入:"abc" → 输出:true
  • 输入:"aba" → 输出:false

3. 示例分析
  1. 无重复字符
    • "leetcode"false'e'重复)
    • "abc"true
  2. 边界情况
    • 空字符串 ""true
    • 字符串长度超过 26 → false(26 个小写字母最多只能有 26 个唯一字符)

4. 算法思路

核心思想位图法(Bitmask)

  1. 位图表示
    • 使用一个整数 flag 的二进制位表示字符是否出现过。
    • 每个二进制位对应一个小写字母,例如:
      • a → 第 0 位
      • b → 第 1 位
      • z → 第 25 位
  2. 遍历字符串
    • 若当前字符对应的二进制位为 1,说明已重复,返回 false
    • 否则,将该位设为 1,继续检查下一个字符。

优化点

  • 预判长度超过 26:若字符串长度超过 26,直接返回 false(鸽巢原理)。
  • 时间复杂度:O(n),空间复杂度:O(1)(仅需一个整数)。

5. 边界条件与注意事项
  1. 字符串长度
    • 若长度超过 26,直接返回 false
    • 空字符串直接返回 true
  2. 字符范围
    • 题目假设字符均为小写字母,若存在其他字符(如大写字母或符号),需预处理为小写。
  3. 位运算溢出
    • 移位操作 1 << ii 的范围需为 0~25,否则可能导致整数溢出。

6. 代码实现
class Solution {
public:
    bool isUnique(string astr) 
    {
        if (astr.size() > 26) return false; // 鸽巢原理优化
        
        int flag = 0; // 位图初始化
        for (char ch : astr) 
        {
            int i = ch - 'a'; // 计算字符对应的二进制位
            if ((flag >> i) & 1) 
            { // 判断该位是否为1
                return false;
            }
            flag |= (1 << i); // 将该位设为1
        }
        return true;
    }
};

与其他方法的对比

方法时间复杂度空间复杂度适用场景
位图法O(n)O(1)仅限小写字母
哈希表法O(n)O(26)所有字符类型
数组计数法O(n)O(26)字符范围明确且较小
暴力枚举法O(n²)O(1)极短字符串(n ≤ 10)

关键代码解析

  1. 位运算检查重复

    if ((flag >> i) & 1) // 判断第i位是否为1
    
    • flag 右移 i 位后,与 1 按位与,结果为 1 则说明该位已被占用。
  2. 位图更新

    flag |= (1 << i); // 将第i位设为1
    
    • 1 左移 i 位后,与 flag 按位或,确保第 i 位被标记为已使用。

总结

位图法通过巧妙的位运算,将空间复杂度降至 O(1),同时保持线性时间复杂度。在面对限定字符范围的问题时(如小写字母、数字等),位图法是最优解之一。其核心在于将字符映射到整数的二进制位上,利用位运算的原子性快速判断重复性。实际应用中,需注意字符范围与整数位数的限制(例如,32 位整数最多覆盖 32 种字符)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值