力扣242. 有效的字母异位词

题目

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的 字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

提示:

  • 1 <= s.length, t.length <= 5 * 104
  • s 和 t 仅包含小写字母

进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

详解

异或法

首先看到这个题目就想起来了刚刚写过的异或运算:力扣389.找不同-优快云博客

 所以这一题是不是也可以直接异或看结果是否为0呢?就像这样:

class Solution {
    public boolean isAnagram(String s, String t) {
        char c = 0;
        int len1 = s.length();
        int len2 = t.length();
        //记录len为len1、len2中最长的
        int len = Math.max(len1,len2);
        for (int i =0;i< len;i++){
            if (i<len1){
                c ^= s.charAt(i);
            }
            if (i<len2){
                c ^= t.charAt(i);
            }
        }
        if(c == 0){
            return true;
        }else {
            return false;
        }
    }
}

提交结果发现

解答错误

41 / 52 个通过的测试用例

原因是

解法使用了异或运算来判断两个字符串是否是字母异位词,这种方法在某些情况下可能会出错。具体来说,如果两个字符串长度相同,并且它们的字符异或结果为0,那么它们有可能是字母异位词。然而,这种判断方法不够严谨,因为不同的字符组合可能会导致相同的异或结果。

例如,考虑字符串 "ab" 和 "cc",它们的异或结果也是0,但它们并不是字母异位词。因此,这种方法存在误判的风险。

排序比较法

  1. 检查两个字符串的长度是否相同。如果不同,直接返回 false
  2. 将两个字符串的字符排序,然后比较排序后的结果是否相同。如果相同,则它们是字母异位词。
import java.util.Arrays;

class Solution {
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        
        char[] sArray = s.toCharArray();
        char[] tArray = t.toCharArray();
        
        Arrays.sort(sArray);
        Arrays.sort(tArray);
        
        return Arrays.equals(sArray, tArray);
    }
}

 Arrays.sort(sArray);此方法是排序的常用方法;

进阶

如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

这个问题我也尝试了好久,发现上述排序比较法使用toCharArray()方法进行排序的时候,在某些特定的情况下会存在问题,特别是当字符串中包含Unicode补充字符(Supplementary Characters) 时,比如一些 emoji、罕见汉字、特殊符号等。

toCharArray 的适用场景(不会有问题)

  • 普通英文字符(如 a-z, A-Z

  • 常见的中日韩文字(位于 BMP,即基本多文种平面)

  • 一般符号和数字(如 #, 1, @ 等)

可能出问题的场景:包含 Unicode 补充字符(> U+FFFF)

例如

String str = "a😊b"; char[] chars = str.toCharArray(); System.out.println(Arrays.toString(chars));

输出为:

[a, \ud83d, \ude0a, b]

  • 😊(Unicode U+1F60A)被拆成两个 char:\ud83d\ude0a(代理对)

  • 排序后可能变成:\ude0a, a, b, \ud83d —— 导致字符显示异常甚至乱码。

 

推荐方案(安全排序方式)

int[] codePoints = str.codePoints().toArray();
Arrays.sort(codePoints);
String sorted = new String(codePoints, 0, codePoints.length);
System.out.println(sorted);

这个方案能正确识别和排序所有字符,不会破坏 emoji 等特殊字符。


总结

方法能否安全排序包含 Unicode 的字符串说明
toCharArray() + Arrays.sort()不推荐会拆开代理对,造成错误排序或乱码
codePoints() + Arrays.sort()推荐正确处理所有 Unicode 字符,包括 emoji


如果只处理英文和常见中文,用 toCharArray() 没问题;如果你要考虑 emoji、特殊符号或国际化,务必用 codePoints()

 

LeetCode 上,第 100 题是“相同的树”(Same Tree),而“字母异位词分组”是 LeetCode 第 49 题[^1]。因此,可能存在对题号的混淆。下面将分别讨论这两道题的相关解法和背景。 ### 1. LeetCode 第 49 题:字母异位词分组(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),取决于树的高度。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值