力扣49-字母异位分组(哈希表 Java详细注释)

本文解析了力扣第49题“字母异位分组”的两种解题思路:逐一比对法和哈希表法,并通过示例展示了如何利用哈希表优化性能。

力扣49-字母异位分组

一、原题题目

1.1 题目

  给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

1.2 示例

  • 示例1:

    输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”]

    输出:

    [
      ["ate","eat","tea"],
      ["nat","tan"],
      ["bat"]
    ]
    

说明:

  • 所有输入均为小写字母。

  • 不考虑答案输出的顺序。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/group-anagrams/

二、解题思路一

2.1 题目意思理解

  这道题题目意思比较简单,即单词的字母组成上相同的但排列顺序不同的分为一个组,遍历每一个单词和保存结果lists中的每一个组中单词是不是异位的,是则加入改组,不是则判断下一组,直到遍历完存在的所有组,则创建一个新组加入。

2.2 详细代码(Java)

public class Solution {
    public static List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> lists = new ArrayList<>();       // 定义保存结果的 lists
        for (int i = 0;i<strs.length;i++){                  // 遍历每一个单词
            boolean flag = false;                           // 记录是否有加入已经存在的组
            for (List<String> list : lists) {               // 遍历lists中的每一个组
                if (isSameWords(strs[i],list.get(0)))   {   // 判断当前组的第一个单词和遍历的单词是否异位
                    list.add(strs[i]);                      // 是异位则加入该组
                    flag = true;                            // 状态改为已加入组的状态
                    continue;                               // 跳过后面的组
                }
            }
            if (flag == false) {    // 没有加入组,说明没有与任何已经存在的组异位,自己独自建组加入lists
                List<String> list = new ArrayList<>();
                list.add(strs[i]);
                lists.add(list);
            }
        }
        return lists;           // 最终返回lists
    }
    public static boolean isSameWords(String word1,String word2){   // 判断两个单词是否异位
        if (word1.length()!= word2.length())    return false;
        char[] chars1 = word1.toCharArray();
        char[] chars2 = word2.toCharArray();
        Arrays.sort(chars1);
        Arrays.sort(chars2);
        return String.valueOf(chars1).equals(String.valueOf(chars2));
    }
}

2.3 算法执行结果

算法执行结果

  结果比较惨,但还好也是自己很快就相处来的方法,接着再思考思考提升下性能。

三、解题思路二(哈希表)

3.1 题目意思理解

  大概意思跟上一种思路一致,用哈希表来存储结果,每一个单词先转换成字符数组,然后排序,再把排序后的字符数组转换成字符串作为同类异位单词的 key ,组作为 value。例如示例:[“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],对于 “eat” 和 “tea” 单词他们转化求 key 都是 “aet” ,即属于同一个组。

3.2 详细代码(Java)

public class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<String,List<String>> hashMap = new HashMap<>();     // 定义哈希表存储分组结果
        for (int i =0 ;i<strs.length;i++){              // 遍历每一个单词
            char[] chars = strs[i].toCharArray();       // 单词转换成字符数组
            Arrays.sort(chars);                         // 对单词字符数组排序
            String key = new String(chars);             // 得到单词对应的 key 
            if (hashMap.containsKey(key)){              // 如果这个 key 在哈希表中存在 
                List<String> list = hashMap.get(key);   // 取出 key 对应的组 
                list.add(strs[i]);                      // 将该单词加入到这个组 
            }
            else {                                          // 如果这个 key 在哈希表中不存在 
                ArrayList<String> list = new ArrayList<>(); // 要新创建一个组
                list.add(strs[i]);                          // 新创建的组中加入该单词
                hashMap.put(key,list);                      // 新创建的组加入哈希表中
            }
        }
        List<List<String>> result = new ArrayList<>(hashMap.values());  // 哈希表值的部分转换成需要输出的格式
        return result;
    }
}

3.3 算法执行结果

改进算法执行结果

  这个结果还行,两种方法思路上差别还是存在很大差距的,哈希表的运用大幅度提升了性能。

LeetCode 上,第 100 题是“相同的树”(Same Tree),而“字母异位分组”是 LeetCode49 题[^1]。因此,可能存在对题号的混淆。下面将分别讨论这两道题的相关解法和背景。 ### 1. LeetCode49 题:字母异位分组(Group Anagrams) **题目描述** 给定一个字符串数组,将所有字母异位词(anagram)组合在一起。字母异位词是指由相同字母不同顺序构成的字符串。 **解法思路** 解决该问题的核心思想是:**字母异位词在排序后具有相同的字符串形式**。因此,可以利用哈希表(Map)来将相同排序后的字符串作为键,对应的原始字符串列表作为值。 #### Java 解法示例(排序 + 哈希表) ```java class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> map = new HashMap<>(); for (String str : strs) { char[] arr = str.toCharArray(); Arrays.sort(arr); String key = new String(arr); List<String> list = map.getOrDefault(key, new ArrayList<>()); list.add(str); map.put(key, list); } return new ArrayList<>(map.values()); } } ``` #### Java 解法示例(计数 + 哈希表) 该方法适用于字符集较大的情况,例如 Unicode 字符。它基于字符出现的频率构建键值。 ```java public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> map = new HashMap<>(); for (String str : strs) { int[] count = new int[26]; for (char c : str.toCharArray()) { count[c - 'a']++; } StringBuilder key = new StringBuilder(); for (int i = 0; i < 26; i++) { key.append(count[i]).append('#'); } String keyStr = key.toString(); if (!map.containsKey(keyStr)) { map.put(keyStr, new ArrayList<>()); } map.get(keyStr).add(str); } return new ArrayList<>(map.values()); } ``` **时间复杂度分析** - 排序法:O(n * k log k),其中 `n` 是字符串数量,`k` 是字符串的最大长度。 - 计数法:O(n * k),其中 `k` 是字符串的平均长度,适用于较长字符串的情况。 **空间复杂度** - O(n * k),用于存储哈希表中的键值对。 ### 2. LeetCode 第 100 题:相同的树(Same Tree) **题目描述** 给定两棵二叉树,判断它们是否相同。两棵树相同当且仅当它们的结构相同,并且每个节点的值也相同。 **解法思路** 可以通过递归或迭代的方式比较两棵树的每个节点: - 如果当前节点都为空,则相同。 - 如果一个为空而另一个非空,则不相同。 - 如果节点值不同,则不相同。 - 否则递归比较左右子树。 #### Java 解法示例(递归) ```java public boolean isSameTree(TreeNode p, TreeNode q) { if (p == null && q == null) return true; if (p == null || q == null) return false; return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right); } ``` #### Java 解法示例(迭代,使用队列) ```java public boolean isSameTree(TreeNode p, TreeNode q) { Queue<TreeNode> queue = new LinkedList<>(); queue.offer(p); queue.offer(q); while (!queue.isEmpty()) { TreeNode node1 = queue.poll(); TreeNode node2 = queue.poll(); if (node1 == null && node2 == null) continue; if (node1 == null || node2 == null || node1.val != node2.val) return false; queue.offer(node1.left); queue.offer(node2.left); queue.offer(node1.right); queue.offer(node2.right); } return true; } ``` **时间复杂度** - O(n),其中 `n` 是树的节点数。 **空间复杂度** - 最坏情况下为 O(n),取决于树的高度。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ItDaChuang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值