news 2026/5/13 0:54:22

【码道初阶】【LeetCode387】如何高效找到字符串中第一个不重复的字符?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【码道初阶】【LeetCode387】如何高效找到字符串中第一个不重复的字符?

算法精解:如何高效找到字符串中第一个不重复的字符?

在处理字符串处理类算法题时,“频率统计”是一个核心思想。今天我们将通过LeetCode 387. 字符串中的第一个唯一字符这道经典题目,深入探讨两种主流解法:数组映射法HashMap 计数法

1. 题目描述

给定一个字符串s,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回-1

示例:

  • 输入:s = "leetcode"-> 输出:0
  • 输入:s = "loveleetcode"-> 输出:2
  • 输入:s = "aabb"-> 输出:-1

提示:

  • s只包含小写字母。
  • 字符串长度可达10510^5105

2. 核心解题思路:两次遍历

无论是使用数组还是 HashMap,其核心逻辑都是相同的,即**“空间换时间”**。

  1. 第一轮遍历:扫描整个字符串,统计每个字符出现的总次数。
  2. 第二轮遍历:再次按索引顺序扫描字符串,检查当前字符在统计表中的次数是否为 1。第一个满足条件的索引即为答案。

3. 解法一:数组映射法(常规方法)

代码实现

classSolution{publicintfirstUniqChar(Strings){// 因为小写字母 ASCII 码或扩展 ASCII 范围内,256 足够覆盖int[]count=newint[256];// 1. 统计频率for(inti=0;i<s.length();i++){count[s.charAt(i)]++;}// 2. 查找第一个频率为 1 的字符索引for(inti=0;i<s.length();i++){if(1==count[s.charAt(i)])returni;}return-1;}}

深度解析

  • 原理:数组本质上是一个简单的哈希表。字符的 ASCII 值作为数组的下标(Index),数组存储的值(Value)则是出现的次数。
  • 空间优化:题目提示只包含小写字母,其实可以使用int[26]的数组,通过s.charAt(i) - 'a'将字符映射到 0-25 索引。使用int[256]更加通用,可以处理所有标准 ASCII 字符。
  • 优点:访问数组的时间复杂度是O(1)O(1)O(1),且没有哈希冲突和额外的对象开销,执行速度极快。

4. 解法二:HashMap 计数法

代码实现

classSolution{publicintfirstUniqChar(Strings){// 使用 HashMap 存储字符及其出现次数HashMap<Character,Integer>count=newHashMap<>();// 1. 统计频率for(inti=0;i<s.length();i++){charc=s.charAt(i);// 如果不存在则存入1,存在则在原值基础上+1count.put(c,count.getOrDefault(c,0)+1);}// 2. 查找第一个频率为 1 的字符索引for(inti=0;i<s.length();i++){if(count.get(s.charAt(i))==1)returni;}return-1;}}

深度解析

  • 原理:利用HashMap的键值对(Key-Value)结构。Key 存储字符Character,Value 存储该字符出现的次数Integer
  • 代码逻辑:
    • count.getOrDefault(c, 0) + 1是一个优雅的写法,它代替了if(!containsKey)的条件判断,使代码更简洁。(虽然也可以使用HashMap的containsKey方法来检测是不是已经有了某个字符,但getOrDefault方法明显更加先进,直接内含了判断字符是否存在的逻辑,是就返回value(题中代码是返回的value+1),不存在就返回默认value(0)(题中代码在key不存在时,首次加入key的value也是0+1))
  • 优点:
    1. 通用性强:如果题目要求处理的是中文字符、特殊符号或任意 Unicode 字符,数组法会因为范围太大失效,而HashMap可以轻松应对。
    2. 易读性:键值对语义明确,代码逻辑更符合直觉。

5. 两种解法对比分析

维度解法一:数组 (Array)解法二:HashMap
时间复杂度O(N)O(N)O(N)- 遍历两次字符串O(N)O(N)O(N)- 遍历两次字符串
空间复杂度O(1)O(1)O(1)- 固定大小 (256 或 26)O(1)O(1)O(1)O(k)O(k)O(k)- 字符集大小
实际效率极高(直接内存访问)一般(涉及对象开销、哈希计算)
适用场景字符范围固定(如仅字母/ASCII)字符范围未知或非常分散(如全 Unicode)

为什么数组通常更快?

在 Java 中,HashMap需要对基本类型进行装箱(intInteger),并且在计算哈希槽、处理链表或红黑树结构时有额外的计算开销。而数组是连续的内存空间,CPU 缓存命中率更高。


6. 总结

  • 如果面试题限制了小写字母,优先选择数组法,它的性能表现最完美。
  • 如果面试题扩展到任意字符或需要更高的代码通用性,使用HashMap是更成熟的工程实践。

核心套路牢记:凡是涉及“第一个唯一”、“重复元素”、“频率统计”的问题,空间换时间(哈希思想)永远是你的首选策略!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/28 4:50:47

GPT-SoVITS语音合成服务等级协议(SLA)范本

GPT-SoVITS语音合成服务等级协议&#xff08;SLA&#xff09;范本 在智能语音交互日益普及的今天&#xff0c;用户对个性化、自然化语音输出的需求正以前所未有的速度增长。无论是虚拟主播的一句问候&#xff0c;还是AI客服流畅的应答&#xff0c;背后都依赖于高度拟人化的语音…

作者头像 李华
网站建设 2026/5/9 12:18:17

GPT-SoVITS语音合成绿色计算:能效比优化策略

GPT-SoVITS语音合成绿色计算&#xff1a;能效比优化策略 在智能客服、虚拟主播和有声内容创作日益普及的今天&#xff0c;用户不再满足于“能说话”的机器语音&#xff0c;而是期待自然、个性、富有情感的声音表达。传统语音合成系统往往依赖大量标注语音数据进行训练&#xff…

作者头像 李华
网站建设 2026/4/18 6:28:51

IAR调试基础操作:单步执行与断点设置图解

深入掌握 IAR 调试核心&#xff1a;单步执行与断点的艺术在嵌入式开发的世界里&#xff0c;代码写完只是开始。真正考验工程师功力的&#xff0c;是当程序跑飞、中断不进、变量突变时&#xff0c;能否迅速定位问题根源——而这&#xff0c;正是调试的价值所在。IAR Embedded Wo…

作者头像 李华
网站建设 2026/5/12 8:55:53

GPT-SoVITS模型备份与恢复:防止训练成果丢失

GPT-SoVITS模型备份与恢复&#xff1a;防止训练成果丢失 在语音合成技术快速演进的今天&#xff0c;个性化声音克隆已不再是科幻电影中的桥段。只需一段短短一分钟的清晰录音&#xff0c;普通人也能拥有属于自己的“数字声纹”。开源项目 GPT-SoVITS 正是这一趋势下的明星方案—…

作者头像 李华
网站建设 2026/5/12 18:17:43

STM32低功耗模式下LED工作策略分析

STM32低功耗模式下如何让LED“既看得见又省电”&#xff1f;你有没有遇到过这样的场景&#xff1a;一个电池供电的STM32设备&#xff0c;明明大部分时间都在“睡觉”&#xff0c;可续航就是不如预期&#xff1f;排查一圈后发现——罪魁祸首竟是那个小小的LED指示灯。它亮着的时…

作者头像 李华
网站建设 2026/5/4 16:27:35

GPT-SoVITS支持ROCm吗?AMD显卡运行可行性

GPT-SoVITS 能在 AMD 显卡上跑吗&#xff1f;ROCm 支持深度解析 在 AI 语音合成技术飞速发展的今天&#xff0c;个性化音色克隆已不再是科研实验室的专属。像 GPT-SoVITS 这类开源项目&#xff0c;仅需一分钟语音样本就能训练出高度拟真的声音模型&#xff0c;正被广泛用于虚拟…

作者头像 李华