导读:本期聚焦于小伙伴创作的《如何用Java实现无排序的同字母异位词分组?字符计数与哈希映射详解》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用Java实现无排序的同字母异位词分组?字符计数与哈希映射详解》有用,将其分享出去将是对创作者最好的鼓励。

Java实现无排序分组同字母异位词:哈希映射与字符计数详解

在字符串处理场景中,我们经常需要将同字母异位词分组。同字母异位词指的是字母相同但排列顺序不同的单词,例如"eat"、"tea"、"ate"都属于同一组同字母异位词。常见的思路是先对单词排序,再用排序后的结果作为分组键,但排序操作会增加时间复杂度。本文将介绍一种无需排序,通过字符计数结合哈希映射实现分组的方法,时间复杂度更低,逻辑也更清晰。

核心思路解析

无需排序的核心逻辑是:每个单词的字母组成是固定的,我们可以统计每个单词中26个小写字母的出现次数,将这个计数结果作为该单词的唯一标识。因为同字母异位词的字母计数完全一致,所以可以用计数结果作为哈希映射的键,将对应的单词放到同一个分组中。

具体实现步骤如下:

  • 遍历所有待分组的单词,对每个单词进行字符计数,统计26个小写字母的出现次数
  • 将计数结果转换为可哈希的字符串形式,作为当前单词的分组键
  • 使用哈希映射存储键到对应单词列表的映射关系,如果键已存在就将单词加入对应的列表,不存在则新建列表
  • 最后将哈希映射中的所有值(即分组后的单词列表)收集起来返回

完整代码实现

下面是完整的Java实现代码,包含详细的注释说明每一步的逻辑:

import java.util.*;

public class GroupAnagrams {
    public List<List<String>> groupAnagrams(String[] strs) {
        // 哈希映射:键为计数结果字符串,值为同字母异位词组成的列表
        Map<String, List<String>> map = new HashMap<>();
        
        for (String str : strs) {
            // 统计26个小写字母的出现次数
            int[] count = new int[26];
            for (char c : str.toCharArray()) {
                count[c - 'a']++;
            }
            
            // 将计数数组转换为字符串作为键,格式为"次数1#次数2#...#次数26"
            StringBuilder keyBuilder = new StringBuilder();
            for (int i = 0; i < 26; i++) {
                keyBuilder.append(count[i]).append("#");
            }
            String key = keyBuilder.toString();
            
            // 如果键不存在,新建列表并放入映射
            if (!map.containsKey(key)) {
                map.put(key, new ArrayList<>());
            }
            // 将当前单词加入对应的分组列表
            map.get(key).add(str);
        }
        
        // 返回所有分组结果
        return new ArrayList<>(map.values());
    }
    
    // 测试示例
    public static void main(String[] args) {
        GroupAnagrams solution = new GroupAnagrams();
        String[] testStrs = {"eat", "tea", "tan", "ate", "nat", "bat"};
        List<List<String>> result = solution.groupAnagrams(testStrs);
        
        System.out.println("分组结果:");
        for (List<String> group : result) {
            System.out.println(group);
        }
    }
}

代码逻辑说明

上述代码中,我们首先创建了一个HashMap用来存储分组映射。遍历每个输入的单词时,先初始化一个长度为26的int数组,用来记录每个字母的出现次数:因为单词只包含小写字母,所以字符c减去'a'就能得到对应的数组下标,对应位置的次数加1。

接下来需要将计数数组转换为字符串作为哈希键。这里采用"次数#次数#..."的格式,比如单词"eat"的计数数组中,e(下标4)对应1,a(下标0)对应1,t(下标19)对应1,其余都是0,转换后的键就是"1#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#0#0#0#",只要是两个同字母异位词,得到的这个键一定完全相同。

之后检查哈希映射中是否已经存在这个键,如果不存在就新建一个空列表放入映射,再把当前单词加入对应的列表。最后只需要把映射中的所有值收集起来,就是最终的分组结果。

复杂度分析

假设输入数组长度为n,每个单词的平均长度为k:

  • 时间复杂度:遍历所有单词需要O(n),每个单词统计字符需要O(k),转换键需要O(26)也就是常数时间,所以整体时间复杂度是O(n*k)
  • 空间复杂度:哈希映射需要存储所有的单词,所以空间复杂度是O(n*k),用来存放所有单词的字符串

对比先排序再分组的O(n*k log k)时间复杂度,这种方法在处理较长单词时性能优势会更明显,同时避免了排序操作带来的额外开销。

边界情况处理

实际使用中还需要考虑一些边界场景:

  • 如果输入数组为空,方法会直接返回空的列表集合,不会出现空指针异常
  • 如果单词包含大写字母或其他字符,上述代码只处理小写字母的情况,实际使用时可以根据需求扩展计数数组的长度,比如扩展到128位处理ASCII字符,或者增加大小写转换的逻辑
  • 如果输入的单词有重复,比如两个相同的"eat",它们会被分到同一个分组中,符合预期的分组逻辑

这种方式不需要对单词本身做任何修改,也不依赖排序操作,逻辑直观且效率稳定,适合大多数同字母异位词分组的场景。

Java同字母异位词分组字符计数哈希映射无排序算法字符串处理修改时间:2026-05-24 12:23:43

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。