欢迎光临
我们一直在努力

算法学习day4--字母异位词哈希计数解法

算法学习day4–字母异位词哈希计数解法

引入

「有效的字母异位词」是哈希计数思想的入门经典题:给定两个字符串 s 和 t,判断 t 是否是 s 的字母异位词——即两个字符串包含的字母种类和数量完全相同,只是顺序可能不同。例如 listen 和 silent 是异位词,rat 和 car 不是。

这道题本身不难,但它示范了一个高频套路:「判断组成是否相同」类问题,优先考虑频次统计。学会之后,“找字符串中第一个只出现一次的字符”、“两个数组的交集”、" ransom note 能否由杂志字母拼出" 等一系列题都是同一个思路的变体。

先想暴力:排序对齐

最直觉的解法:如果两个串是异位词,那把字符排序后一定完全相等。

fun isAnagramSort(s: String, t: String): Boolean {
if (s.length != t.length) return false
return s.toCharArray().sorted().joinToString("") ==
t.toCharArray().sorted().joinToString("")
}

  • 正确性没问题;
  • 复杂度是 O(n log n) 时间(排序主导)、O(n) 额外空间。
  • 瓶颈在于:我们其实不需要知道「字母的顺序关系」,只需要「每个字母出现了几次」。排序做了大量无用功——这正是优化的切入点。

更优解:数组频次计数

小写字母只有 26 种,用一个长度 26 的数组当计数器即可:

fun isAnagram(s: String, t: String): Boolean {
if (s.length != t.length) return false

val count = IntArray(26)
for (c in s) count[c – 'a']++ // s 的字母 +1
for (c in t) count[c – 'a']— // t 的字母 -1

return count.all { it == 0 } // 全为 0 说明频次完全抵消
}

思路拆解:

  • 长度不等直接返回 false——这是最容易漏掉的提前剪枝,长度都不同不可能互为异位词;
  • c – 'a' 把字符映射到数组下标:'a' → 0,'b' → 1,以此类推。字符本身没有数学意义,但字符之间的偏移量有,这是字符题映射下标的通用手法;
  • 对 s 加、对 t 减,最后数组全零 ⇔ 两个串每个字母出现次数相等。
  • 也可以写成一次遍历的版本(下标从 0 走到 n,同时加 s[i] 减 t[i]),逻辑等价。

    复杂度与解法对比

    解法时间额外空间备注
    排序后比较 O(n log n) O(n) 直觉解,代码短
    数组计数 O(n) O(1)(26 长度定长数组) 最优,前提是字符集小
    哈希表计数 O(n) O(k),k 为字符种类数 字符集大(Unicode)时用它

    工程上的取舍:题目限定小写字母时数组计数是最优解;如果字符可能是任意 Unicode(中文、emoji),26 长度数组不够,应换成 HashMap<Char, Int> 计数——思想完全相同,只是容器从数组换成哈希表。

    一个细节:如果这题改成「找出 s 中 t 的所有异位词起始下标」(LeetCode 438),就还要在计数数组上做滑动窗口增量更新,而不是每次重建计数——这也是计数思想往中档题进阶的方向。

    实际场景

    • 敏感词/相似度检测:判断两段文本用词组成是否一致(打乱顺序规避检测的场景);
    • 数据校验:校验重排后的日志行是否丢失/多出内容(频次 diff);
    • 缓存键归一化:把「组成相同」的对象归一到同一个 key,比如把字母集合排序后作为分组键(LeetCode 49 字母异位词分组就是干这个)。

    可迁移套路

    这题提炼出的可迁移套路一句话:「比较组成而不比较顺序 → 频次统计」。

    具体动手模板:

  • 问自己:这题在乎顺序吗?——异位词不在乎顺序,排序是浪费;
  • 字符集有多大?——小写字母 26 → 定长数组;任意字符 → 哈希表;
  • 一次加一次减,最后检查归零,或维护一个「非零计数器」实时判断。
  • 后续的「 ransom note 」(单向频次扣减)、「第一个只出现一次的字符」(频次 + 首次位置)、「字母异位词分组」(排序串作哈希键)都是这个模板的直接应用。

    小结

    • 有效的字母异位词 = 两个串字母频次完全相同;
    • 排序法 O(n log n) 是直觉解;数组计数法 O(n) + O(1) 空间才是最优解;
    • 关键技巧:c – 'a' 做字符到下标的映射;先判长度做剪枝;
    • 核心套路「比较组成 → 频次统计」,字符集大时把数组换成哈希表即可平移到更复杂的题目上。
    赞(0)
    未经允许不得转载:171主机测评 » 算法学习day4--字母异位词哈希计数解法
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址