news 2026/9/11 8:24:24

LeetCode 242. Valid Anagram 题解:Go 实现字母异位词判断的计数法原理与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 242. Valid Anagram 题解:Go 实现字母异位词判断的计数法原理与实战

LeetCode 242. Valid Anagram 题解:Go 实现字母异位词判断的计数法原理与实战

【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go

导读

本文围绕 LeetCode 第 242 题「有效的字母异位词(Valid Anagram)」展开,以本仓库(LeetCode-Go)中该题的官方题解文档与 Go 源码为骨架,完整讲解题目约束、计数打表法的核心思路、两种 Go 实现(定长数组计数与哈希表计数)、边界条件与测试用例,并顺带剖析 Follow up 中 Unicode 场景的适配方案。读完本文,你将掌握字母异位词判定的标准套路,并能举一反三应用到字母异位词分组等进阶题型中。

题目原文与核心考点

题目定义如下:给定两个字符串st,编写一个函数判断t是否为s的字母异位词(anagram)。原题给出的两个示例为:

Input: s = "anagram", t = "nagaram" Output: true
Input: s = "rat", t = "car" Output: false

第一组示例中,"nagaram""anagram"的字母重新排列而成(a、n、a、g、r、a、m 六个字母逐一对应),因此返回true;第二组示例中"rat""car"的字符构成不一致,返回false

题目还附带两个重要说明:

  • Note:可以假设输入字符串仅包含小写字母(lowercase alphabets),这是选择定长数组解法的前提条件;
  • Follow up:如果输入包含 Unicode 字符,应该如何调整解法?

题目大意(中文释义)

题解文档给出的中文概括为:给出 2 个字符串st,如果t中的字母在s中都存在,输出true,否则输出false。更严谨地说,字母异位词要求两个字符串长度相同、字符构成完全相同、仅排列顺序不同——这一点从仓库测试用例{"", "1"}{"a", "ab"}均返回false可以得到印证。

解题思路:计数打表法

题解文档给出的核心思路是计数打表(counting with lookup table),流程分三步:

  1. 先建立一个容量为 26 的数组,下标依次对应 26 个小写字母(0对应a25对应z);
  2. 扫描字符串s,每遇到一个字母,就在对应下标处加 1;
  3. 再扫描字符串t,每遇到一个字母,就在对应下标处减 1。

如果ts的字母异位词,那么t中每个字母的出现次数必然与s完全一致,经过"先加后减"的抵消后,表中所有值都应归零;反之,只要表中存在非 0 值,就说明两个字符串的字符计数不一致,输出false

该方法的时间复杂度为 O(n)(只需线性扫描两遍字符串,且每遍操作均为 O(1) 的数组下标访问),空间复杂度为 O(1)(固定 26 个整数的数组,与输入规模无关)。

源码实现一:定长数组计数(小写字母场景)

仓库解法一实现了上述打表思路,完整代码如下(见 242. Valid Anagram.go):

// 解法一 func isAnagram(s string, t string) bool { alphabet := make([]int, 26) sBytes := []byte(s) tBytes := []byte(t) if len(sBytes) != len(tBytes) { return false } for i := 0; i < len(sBytes); i++ { alphabet[sBytes[i]-'a']++ } for i := 0; i < len(tBytes); i++ { alphabet[tBytes[i]-'a']-- } for i := 0; i < 26; i++ { if alphabet[i] != 0 { return false } } return true }

对这段代码的逐步拆解:

  • alphabet := make([]int, 26):创建定长计数数组,零值即初始计数 0;
  • 长度预检len(sBytes) != len(tBytes):长度不同的两个字符串不可能互为字母异位词,直接短路返回false,省去后续全部扫描;
  • sBytes[i]-'a':利用 ASCII 码连续性,把字符'a'~'z'映射到数组下标0~25。这也是题目要求"仅含小写字母"的原因——若输入混入大写字母或数字,该偏移计算会越界或错位;
  • 先对s全体++,再对t全体--,最终遍历 26 个槽位,存在非 0 即返回false

源码实现二:哈希表计数(通用字符场景)

仓库解法二改用map[rune]int替代定长数组,完整代码如下(见 242. Valid Anagram.go):

// 解法二 func isAnagram1(s string, t string) bool { hash := map[rune]int{} for _, value := range s { hash[value]++ } for _, value := range t { hash[value]-- } for _, value := range hash { if value != 0 { return false } } return true }

与解法一相比,这里有两个关键差异:

  1. 按 rune 迭代而非按 byte 迭代range在字符串上迭代时解出的是 Unicode 码点(rune),天然按字符边界切分,不会把多字节 UTF-8 字符拆碎;
  2. 用哈希表动态扩展槽位:字符集不再被限制为 26 个小写字母,任意 Unicode 字符都能作为 key 计数。

这两点使得解法二天然适配题目的 Follow up——当输入包含 Unicode 字符(如中文、emoji、带声调字母)时,只需把解法二中的range改按[]rune(s)迭代,即可正确完成计数。这也印证了仓库中解法一、解法二并存的设计意图:定长数组解法面向"仅小写字母"的标准场景追求极致的 O(1) 空间,哈希表解法面向通用字符场景保证正确性。

测试用例与边界验证

仓库测试文件 242. Valid Anagram_test.go 使用表驱动(table-driven)风格组织用例,覆盖了如下关键场景:

输入s输入t期望输出覆盖的边界
""""true两个空字符串互为异位词
"""1"false长度不等 + 非字母字符
"anagram""nagaram"true题目示例一(正例)
"rat""car"false题目示例二(反例)
"a""ab"false长度不等
"ab""a"false长度不等(长度预检兜底)
"aa""bb"false长度相等但字符构成不同

其中{"aa", "bb"}用例尤其值得注意:它验证了长度相等并不足以判定异位词——两个字符串必须逐字符计数完全一致才行,这正是计数表最终校验"全 0"的意义所在。运行go test执行该测试文件,会依次打印每个用例的输入与输出结果,全部断言通过(仓库目标为 100% 测试覆盖率,该题解法一、解法二均被同一测试集覆盖)。

思路延伸:异位词判定在仓库进阶题中的应用

字母异位词判定的计数思路,在本仓库的进阶题目中有直接延伸。例如 49. Group Anagrams.go 将字符串按 rune 排序后作为哈希 key,把互为异位词的字符串归入同一分组——排序后的字符串本质上是字符计数的另一种等价表达(两个字符串异位词当且仅当它们排序后相等)。该题实现同样通过[]rune(str)处理多字节字符,与解法二的 Unicode 兼容策略一脉相承,可作为读完本题后的下一道练手题。

小结

  • 核心结论:字母异位词判定等价于"字符计数向量相等",用一次加、一次减的抵消操作即可在 O(n) 时间内完成;
  • 适用前提:定长 26 数组解法依赖"仅含小写字母"的题目约束;突破该约束时切换为map[rune]int计数即可,仓库解法二已给出可直接运行的实现;
  • 边界意识:先做长度预检、再校验计数表全 0,两个条件缺一不可,仓库测试用例已完整覆盖这两类反例。

【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

ARM嵌入式AI实战:ML-KWS-for-MCU源码深度解析与内存优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 8:20:08

昇思MindSpore大模型对齐实战:从RLHF到DPO的偏好优化指南

做昇思MindSpore大模型训练的朋友&#xff0c;可能都有过这种时刻&#xff1a;基座模型辛辛苦苦预训练完&#xff0c;loss低得漂亮&#xff0c;给它一句提示词也能生成一大段通顺的文字&#xff0c;可一旦让它"按给定格式输出"或者"只回答要点"&#xff0c…

作者头像 李华
网站建设 2026/9/11 8:19:31

无电无网的野外监控怎么搭?太阳能4G云台半年使用实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 8:16:47

HarmonyOS养老APP开发:三层架构与分布式实践

1. 项目背景与核心价值"益康养老"HarmonyOS APP的开发源于当前老龄化社会对智能化养老服务的迫切需求。作为一款面向老年群体的健康管理应用&#xff0c;它需要解决三个核心问题&#xff1a;操作简易性、数据安全性以及跨设备协同能力。选择HarmonyOS作为开发平台&am…

作者头像 李华
网站建设 2026/9/11 8:14:44

智能体架构三要素:隔离、集成与治理的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华