当前位置: 首页 > news >正文

C++ 位运算 高频面试考点 力扣 01.01 判断字符是否唯一 题解 每日一题

文章目录

  • 题目解析
  • 为什么这道题值得你花几分钟的时间看完?
  • 可以做出这道题的方法
  • 核心解法详解
    • 哈希表
    • 数组模拟哈希(空间优化)
    • 位运算(最优,无额外数据结构)
      • 核心原理(位图思想)
      • 关键位运算操作
      • 代码实现(O(n))
      • 时间复杂度和空间复杂度的分析
  • 其他方法 (对比参考)
    • 暴力遍历(O(n²))
    • 排序+相邻判断(O(n logn))
  • 面试避坑指南
  • 思考题
  • 总结
  • 下题预告

在这里插入图片描述

在这里插入图片描述

题目解析

题目链接:力扣 01.01 判断字符是否唯一
题目描述:
实现一个算法,确定一个字符串 s 的所有字符是否全都不同。
示例 1:
输入: s = "leetcode"
输出: false
示例 2:
输入: s = "abc"
输出: true
限制:
0 <= len(s) <= 100
s[i]仅包含小写字母
如果你不使用额外的数据结构,会很加分。

示例 1:
输入: s = “leetcode”
输出: false
解释:字符串中包含重复的 ‘e’ 和 ‘t’,故返回 false。

示例 2:
输入: s = “abc”
输出: true
解释:字符串中所有字符均不重复,故返回 true。

限制:

  1. 0 <= len(s) <= 100
  2. s[i] 仅包含小写字母
  3. 如果你不使用额外的数据结构,会很加分。

为什么这道题值得你花几分钟的时间看完?

它不是一道普通的算法题,而是面试高频“开胃题”。难度不高,价值却堪称“算法思维试金石”——它用极简的题干,藏住了“从直观到最优”的完整优化链路,能帮你快速复盘算法设计的核心逻辑。

面试官考这道题,从来不是“做出来就行”。他们真正想通过这道题看清你的能力底色,尤其关注三点:

  1. 能否说出3种及以上不同解法,展现思维广度;
  2. 能否精准分析每种解法的时间/空间复杂度,体现基础功底;
  3. 能否结合“仅小写字母”的题目限制,给出“无额外数据结构”的最优解,彰显问题拆解与优化能力。

接下来,我们将从“基础解法”到“进阶最优解”逐步拆解。其中会重点用到位运算技巧——这正是面试中的“隐形加分项”,用好它往往能给面试官留下“算法功底扎实”的第一印象。

如果对位运算的细节有些生疏,建议先结合我的这篇总结复习:位运算 常见方法总结 算法练习。这篇博客可以帮刚接触算法的朋友可以用它捋顺基础,避免后续思路脱节;已有积累的伙伴能借它快速唤醒核心技巧记忆;至于算法大佬,直接往下读即可——当然若您愿意在评论区分享建议,我会万分感激,文中梳理的场景化用法也可供您随手一阅,为后续最优解的推导多添一份顺畅严谨。

可以做出这道题的方法

这道题的解法可按“空间优化程度”分为三个层级,从“直观易想到”到“极致优化”,具体对比如下表:

解法核心逻辑时间复杂度空间复杂度适用场景优势与不足
暴力遍历双层循环,每个字符与后续所有字符对比,存在重复则返回falseO(n²)O(1)数组长度极小(n<10)无额外空间,但时间效率极低
排序+相邻判断先排序(重复字符会相邻),再遍历对比相邻字符是否相同O(n logn)O(logn)对空间要求较低,可接受排序开销实现简单,但依赖排序,修改原字符串
哈希表遍历字符存入哈希表,存入前判断是否已存在,存在则返回falseO(n)O(26)≈O(1)追求时间效率,允许少量空间时间最优,但需额外哈希表结构
数组模拟哈希用26位布尔数组替代哈希表,对应26个小写字母,标记字符是否出现O(n)O(26)≈O(1)已知字符范围(仅小写字母)空间更紧凑,比哈希表更贴合题目限制
位运算(最优)用一个整数的26个二进制位作为“位图”,标记字符是否出现,无额外数据结构O(n)O(1)面试加分项,追求极致空间优化无任何额外数据结构,空间效率拉满

我将在时间复杂度最优的情况下按“空间优化递进”的顺序讲解,重点聚焦数组模拟哈希位运算两种核心解法,最后补充基础解法作为对比。

核心解法详解

哈希表

核心思路

  1. 初始化一个哈希表(如C++的unordered_set<char>);
  2. 遍历字符串s中的每个字符ch
    • ch已在哈希表中,说明存在重复,返回false
    • ch不在哈希表中,将其插入哈希表;
  3. 遍历结束未发现重复,返回true

代码实现(O(n))

#include <unordered_set>
using namespace std;class Solution {
public:bool isUnique(string astr) {unordered_set<char> char_set;for (char ch : astr) {// 若字符已存在,返回falseif (char_set.count(ch)) {return false;}// 字符不存在,插入哈希表char_set.insert(ch);}return true;}
};

数组模拟哈希(空间优化)

哈希表虽高效,但仍属于“额外数据结构”,且存在一定的底层实现开销。由于字符范围固定为“26个小写字母”,我们可以用一个长度为26的布尔数组替代哈希表,进一步压缩空间。

核心思路

  1. 字符映射:将小写字母ch映射为数组下标——index = ch - 'a'(如’a’→0,'b’→1,…,'z’→25);
  2. 初始化布尔数组used[26],全部置为false(表示字符未出现);
  3. 遍历字符串s中的每个字符ch
    • 计算映射下标index
    • used[index]true,说明字符已出现,返回false
    • used[index]false,将其置为true
  4. 遍历结束未发现重复,返回true

代码实现(O(n))

class Solution {
public:bool isUnique(string astr) {bool used[26] = {false}; // 26个小写字母对应26个位置for (char ch : astr) {int index = ch - 'a'; // 字符转下标if (used[index]) {return false; // 已出现过,返回false}used[index] = true; // 标记为已出现}return true;}
};

优势

  • 空间更紧凑:布尔数组仅占用26个字节(哈希表需存储链表/红黑树结构,开销更大);
  • 访问更快:数组下标访问为O(1),比哈希表的哈希计算+冲突处理更高效。

位运算(最优,无额外数据结构)

这是面试中的“加分解法”——利用一个32位整数的二进制位作为“位图”,完全避免额外数据结构,空间复杂度达到理论最优O(1)。

核心原理(位图思想)

32位整数有32个二进制位,而我们仅需26个位即可表示26个小写字母:

  • 用整数map的第i位(从右数)表示第i个小写字母是否出现(如第0位→’a’,第1位→’b’,…);
  • 二进制位为0:字符未出现;二进制位为1:字符已出现。

如图中第三个👇
在这里插入图片描述

关键位运算操作

1. 判断字符是否已出现(位图第i位是否为1)

核心公式(n >> i) & 1(n代表位图,i代表目标位,详细推导可参考位运算 常见方法总结 算法练习)

  • 第一步移位聚焦:将位图n右移i位(n >> i),把要判断的第i位移到二进制数的最右侧,其余高位自动舍弃;
  • 第二步与运算验证:用移位结果与1做“与运算”(& 1)。由于1的二进制只有最右侧为1,仅当目标位原本为1时,结果才会是1(表示字符已出现),否则为0(表示未出现)。

示例:若n=0b101(对应’a’和’c’已标记),判断’c’(对应位i=2):
0b101 >> 2 = 0b10b1 & 1 = 1→ 字符已出现。

2. 标记字符为已出现(将位图第i位改为1)

核心公式n = n | (1 << i)(n代表位图,i代表目标位,详细推导可参考位运算 常见方法总结 算法练习)

  • 第一步构建掩码:将1左移i位(1 << i),得到一个“仅第i位为1、其余位全为0”的二进制数(即掩码);
  • 第二步或运算标记:用位图n与掩码做“或运算”(n | 掩码)。或运算的特性是“有1则1”,能在不改变其他位的前提下,强制将第i位改为1,实现字符标记。

示例:若n=0b101,标记’d’(对应位i=3):
1 << 3 = 0b10000b101 | 0b1000 = 0b1101→ 'd’已成功标记。

代码实现(O(n))

class Solution {
public:bool isUnique(string astr) {int map = 0; // 32位整数,作为26位位图for (char ch : astr) {int i = ch - 'a'; // 字符映射为下标(0-25)// 判断第i位是否为1(字符已出现)if ((map >> i) & 1) {return false;}// 将第i位改为1(标记字符已出现)map |= (1 << i);}return true;}
};

代码解释:

  • map = 0:初始位图全为0(所有字符未出现);
  • i = ch - 'a':核心映射逻辑,将字符转为0-25的整数;
  • (map >> i) & 1:核心判断逻辑,快速检测字符是否重复;
  • map |= (1 << i):核心标记逻辑,更新位图状态。

时间复杂度和空间复杂度的分析

解法时间复杂度空间复杂度关键原因
哈希表O(n)O(1)遍历字符串1次,哈希表最多存26个字符
数组模拟哈希O(n)O(1)遍历字符串1次,数组长度固定为26
位运算O(n)O(1)遍历字符串1次,仅用1个整数,无任何额外数据结构

其他方法 (对比参考)

暴力遍历(O(n²))

最直观但效率最低的解法,适合理解“重复判断”的本质逻辑。

核心思路
双层循环:外层循环遍历每个字符astr[i],内层循环遍历astr[i]之后的所有字符astr[j](j > i),若astr[i] == astr[j]则返回false

代码实现

class Solution {
public:bool isUnique(string astr) {int n = astr.size();for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {if (astr[i] == astr[j]) {return false;}}}return true;}
};

缺点:
时间复杂度O(n²),当n=100时需执行近5000次比较,效率远低于O(n)解法。

排序+相邻判断(O(n logn))

利用“排序后重复字符相邻”的特性,将双层循环优化为单层循环。

核心思路

  1. 对字符串进行排序(如快速排序,时间复杂度O(n logn));
  2. 遍历排序后的字符串,对比相邻字符是否相同,若相同则返回false

代码实现

#include <algorithm>
using namespace std;class Solution {
public:bool isUnique(string astr) {// 排序字符串(重复字符会相邻)sort(astr.begin(), astr.end());int n = astr.size();for (int i = 1; i < n; ++i) {// 相邻字符相同,返回falseif (astr[i] == astr[i-1]) {return false;}}return true;}
};

注意
排序会修改原字符串(若不允许修改,需额外复制一份,空间复杂度变为O(n)),且时间复杂度依赖排序算法,不如哈希/位运算高效。

面试避坑指南

  1. 用排序解法时,若题目要求“不修改原字符串”,需先复制副本(如string sorted_str = astr),否则会因修改输入数据扣分;
  2. 位运算解法中,i的计算必须是ch - 'a'(而非直接用ch),否则会因字符ASCII值超出26位范围,导致位图逻辑错误;
  3. 哈希表解法中,优先选择unordered_set(平均O(1)访问)而非set(O(logn)访问),避免不必要的性能损耗。

思考题

如果用“异或运算”替代“与/或+移位”,能否实现同样的逻辑?下一题“丢失的数字”会带你解锁异或的更多用法~

总结

这道题的本质是“重复检测”,解法的优化路径清晰体现了“时间与空间的权衡”以及“利用题目限制做定制化优化”的算法思想:

  1. 若追求“最简单实现”:选暴力遍历排序+相邻判断
  2. 若追求“时间最优”:选哈希表数组模拟哈希
  3. 若追求“面试加分”:必选位运算(无额外数据结构,空间极致优化)。

核心考点回顾:

  • 字符映射:ch - 'a'是处理小写字母的常用技巧;
  • 位图思想:用二进制位标记状态,是嵌入式、底层开发中的常用优化手段;
  • 复杂度分析:能清晰说明每种解法的优劣,是面试的核心考察点。

下题预告

下一篇博客将讲解力扣 268. 丢失的数字,这道题与今天的“位运算解法”一脉相承,同样可以用“异或特性”实现最优解,同时还能巩固“高斯求和”“哈希表”等多种思路。

http://www.dtcms.com/a/409741.html

相关文章:

  • LeetCode 2825.循环增长使字符串子序列等于另一个字符串
  • JUC CountDownLatch源码详解
  • Unity-动画IK控制
  • 华天软件Inforcenter PLM uploadFileTolls接口存在任意文件上传漏洞
  • FT2000/4核Linux下GPIO中断调试说明
  • 从后端到react框架
  • 几个Linux系统安装体验: 银河麒麟服务器系统V11
  • 金仓数据库打通电子证照国产化“最后一公里”——福建某地2TB MongoDB无缝迁移实践
  • 宁波网站建设明细报价上海红蚂蚁装潢设计有限公司
  • 罗田企业网站建设在贸易网站怎么做贸易
  • 前端登录加密实战:从原理到落地,守护用户密码安全
  • 公司网站域名申请流程江苏营销型网站建设
  • 做外单网站亚马逊如何做ps4的游戏视频网站
  • 企业门户网站建设特色小程序营销策划方案
  • 网站加ico图标如何登陆网站空间
  • 外贸网站建设 东莞企业信息管理系统登录
  • 天津品牌网站建设推广产品吸引人的句子
  • 网站建设价格标准渠道电商设备网站怎么做
  • 秦皇岛网站制作费用服务器维护费用明细
  • 浙江鼎兴建设有限公司网站加强政协机关网站建设
  • 做视频网站 带宽多少才合适谷歌优化推广
  • 网站设计费用入哪个会计科目宜都市网站建设
  • 建标网seo是指什么职位
  • i深圳网站建设wordpress数据库排序规则
  • 服务器做视频网站江苏省宝应城市建设有限公司网站
  • 网站默认图片北京市建设工程第四检测所网站
  • 安网站建设免费一键logo在线设计
  • 数码产品销售网站建设策划书做外贸需要具备什么条件
  • 空间备案网站cms 网站
  • 欧美网站设计风格深圳家具定制