有效的变位词
给定两个字符串s和t,请判断它们是不是一组变位词:在一组变位词中,它们中的字符及每个字符出现的次数都相同,但字符的顺序不能相同。例如,"anagram"和"nagaram"就是一组变位词。
思路
针对变位词的解析可以移步上一小节:关于变位词的解析:厚积薄发打卡Day98:哈希表(三)<字符串变位词>
由于变位词与字符出现的次数相关,因此可以用一个哈希表来储存字符出现的次数:
- 哈希表<字符,字符出现的次数>
实现
数组
如果只考虑小写英文字母,则可以用数组模拟哈希表
-
小写字母为有限集合,可定义容量为26的数组作为哈希表实现:
public class AnagramHash01_Lowercase { public boolean isAnagram(String str1, String str2) { if (str1.length() != str2.length()) { return false; } int[] count = new int[26]; for (char c : str1.toCharArray()) { count[c - 'a']++; } for (char c : str2.toCharArray()) { //如果str2中存在 str1中不存在的char if (count[c - 'a'] == 0) { return false; } count[c - 'a']--; } return true; } public static void main(String[] args) { AnagramHash01_Lowercase hash01Lowercase = new AnagramHash01_Lowercase(); System.out.println(hash01Lowercase.isAnagram("anagram", "nagaram")); } }
-
验证:
-
初始化:
-
接下来遍历字符串”nagaram“:
- 如果遍历到的字符在初始化的哈希容器中为0,那么就说明该字符没有在Str1出现过
- 可以直接return false;
- 否则逐个自减,完成遍历
-
HashMap
如果考虑非英文的字符串,则需用到真正的HashMap
-
字符char可以转换为Unicode编码,一个Unicode编码长度为16位,因此能表示65536个字符
-
如果开辟个长度为65536的数组也可以完成,但这确实会浪费极大的内存,因此用HashMap比较合理
public class AnagramHash01_Unicode { public boolean isAnagram(String str1, String str2) { if (str1.length() != str2.length()) { return false; } HashMap<Character, Integer> counts = new HashMap<>(); for (char c : str1.toCharArray()) { counts.put(c, counts.getOrDefault(c, 0) + 1); } for (char c : str2.toCharArray()) { if (!counts.containsKey(c) || counts.get(c) == 0) { return false; } counts.put(c, counts.get(c) - 1); } return true; } public static void main(String[] args) { AnagramHash01_Unicode hash01Ascii = new AnagramHash01_Unicode(); System.out.println(hash01Ascii.isAnagram("上海自来水", "水来自海上")); } }
-
验证:
-
初始化:
-
遍历str2的字符
- 如果HashMap没有str2的字符作为key,说明不存在该字符
- 如果HashMap有key,但是value为0,说明str1与str2某个字符出现的次数不一致
- 比如s1 = ”你好坏“ 和 s2 = ”你坏坏“
(鬼知道为啥会蹦出这个词) - 这时候遍历s2到第二个”坏“字时会发现之前的”坏“已经被遍历过了,这次就直接返回false即可
- 比如s1 = ”你好坏“ 和 s2 = ”你坏坏“
- 否则继续遍历直至完成即可
-