当前:LC242 · 有效的字母异位词 · 首次出现于 Day 2 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC242 · Valid Anagram · 哈希 / 计数

有效的字母异位词:26 格一加一减

多重集相等 ⇔ 每个字母的出现次数相等。s 里加一、t 里减一,26 格回到全零就是异位词。

长度不同直接假。开 [26]int,同步扫 s 和 t:s 的字母 +1,t 的字母 −1。结束时数组等于零值,则两串字符种类和数量完全一致。时间 O(n),空间 O(1)。字母表不是小写时改用哈希表。

时间 O(n)空间 O(1)结论先行 · 全文约 6 节
导读

这是 LeetCode 242. Valid Anagram。大白话:给两个字符串 s 和 t,判断它们是不是字母异位词——由相同的字母组成,每个字母出现次数也相同,只是顺序可以不同。

主例 s = "anagram",t = "nagaram",都是 a 三个、g、m、n、r 各一个,返回 true。对照 s = "rat",t = "car",字母对不上,返回 false。长度不同也直接假,例如 "ab" 和 "a"。

第一反应是两串都排序再比。正确,但排序构造了全序,题目只要计数。缺口是一张 26 格的差表:一边加一边减,看能不能抵消干净。

判定的是多重集,不是字典序

异位词 ⇔ 两个串作为字符多重集相等。先比长度:长度不同,多重集的基数不同,必假。长度相同再比每种字符的个数。主例长度都是 7,进入计数;rat 和 car 长度都是 3,也要靠计数才能否决。

本题常见约束是小写字母,计数表固定 26 格,额外空间 O(1)。若改成任意 Unicode,26 格不够,要用哈希表,空间随不同字符数增长。面试把这句前提说清楚。

排序后比较:对,但多做了全序

两串排序后相等,则多重集相等。主例 anagram 与 nagaram 都变成 aagmnr,返回 true。演示第一帧是原串,第二帧是排完的 aagmnr 对 aagmnr。rat 与 car 变成 art 与 acr,不相等。

时间 O(n log n)。排序要决定每个位置谁在前,题目并不需要这个顺序,只要个数。它能当对照,不是这道题逼出来的线性写法。

排序后逐字符比较:等价,但排序是 O(n log n) 的额外开销
aagmnr
aagmnr
排序后相同 → 异位词

26 格:s 加一,t 减一,看是否回零

开一张 26 格的表。对每个下标 i,count[s[i]−'a']++,count[t[i]−'a']--。s 贡献正号,t 贡献负号。同一种字母在两边出现次数相同,正负抵消为 0;某一种多出来,对应格子会留下非零。扫完后整表等于零值数组,就是异位词。

用手走主例。演示第一帧表还空,准备从下标 0 加 a。加到下标 3,演示第二帧表上 a、n、g、r 各 1——此时只加了 s 的前几位,t 的减还没抵完。两边都扫完,a 的三次加与三次减抵消,其余字母同样回零。演示第三帧全是 0,op 标成 zero,返回 true。

对照 rat 与 car:r、a、t 各 +1,再 c、a、r 各 −1,留下 t=+1、c=−1,表不是全零,返回 false。长度不同的两串不要进这张表,先在门口挡掉,避免越界或误判。

抵消一加一减是差集为零。不必先统计完整的 s 再统计完整的 t,两个串可以同一下标一起处理,写出来更短。
s 每个字符 +1,t 每个字符 −1:全零即异位词
s
anagram
t
nagaram
计数表
(空)
s 的「a」→ +1

字符集决定这张表怎么开

小写字母:var count [26]int,空间 O(1),还可以用数组相等一次性判断全零。Unicode:改 map[rune]int,最后再扫一遍看是否全零,空间 O(不同字符数)。

LC49 分组用的是同一张判定:排序键或 26 计数键。本题只比较两串,计数表够了,不必真的把键拼出来。

八行 Go:计数表

solution.goGo
func isAnagram(s, t string) bool {
if len(s) != len(t) { return false }
var count [26]int
for i := 0; i < len(s); i++ {
count[s[i]-'a']++
count[t[i]-'a']--
}
return count == [26]int{}
}

1长度不同直接假。主例都是 7,进循环;ab 与 a 不会去减越界。

2同一 i 上 s 加、t 减。主例七次之后 26 格全零。

3return count == [26]int{} 是整表比较。rat/car 会留下 t 和 c 的非零。

4前提是小写字母。字符集变了,这 26 格和 −'a' 一起失效。

总结

长度先挡;26 格 s 加 t 减,全零才是异位词。主例 anagram / nagaram 回零。

  • 排序正确但 O(n log n),构造了题目不需要的顺序。
  • 计数才是多重集判定。主例抵消为 0;rat/car 留下 t=+1、c=−1。
  • 小写字母空间 O(1);Unicode 换哈希表。
同族题目
LC49字母异位词分组LC438找到字符串中所有字母异位词LC567字符串的排列