给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
提示:
1 <= s.length, t.length <= 5 * 104
s 和 t 仅包含小写字母
进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
我的代码:
func isAnagram(s string, t string) bool {
if len(s) != len(t){
return false
}else{
o := make(map[rune]int)
p := make(map[rune]int)
for _, v := range s{
if o[v] != 0{
o[v]++
}else{
o[v] = 1
}
}
for _, v := range t{
if p[v] != 0{
p[v]++
}else{
p[v] = 1
}
}
for i, _ := range o{
if o[i] == p[i]{
}else{
return false;
}
}
return true;
}
}
方法一:排序
t是 s 的异位词等价于「两个字符串排序后相等」。因此我们可以对字符串 s 和 t 分别排序,看排序后的字符串是否相等即可判断。此外,如果 s 和 t 的长度不同,t 必然不是 s 的异位词。
前置知识点;
func Slice(x interface{}, less func(i, j int) bool) // 第一个形参是:待排序数据 x interface{} // 第二个形参是:排序判断方法 // 形参i 代表后一个元素 // 形参j 代表前一元素 // 返回值:代表i,j是否交换。true:交换,false:不交换。 less func(i, j int) bool
func isAnagram(s, t string) bool {
s1, s2 := []byte(s), []byte(t)
sort.Slice(s1, func(i, j int) bool { return s1[i] < s1[j] })
sort.Slice(s2, func(i, j int) bool { return s2[i] < s2[j] })
return string(s1) == string(s2)
}
方法二:哈希表
从另一个角度考虑,t 是 s 的异位词等价于「两个字符串中字符出现的种类和次数均相等」。由于字符串只包含26 个小写字母,因此我们可以维护一个长度为 26 的频次数组table,先遍历记录字符串 s 中字符出现的频次,然后遍历字符串 t,减去 table 中对应的频次,如果出现 table[i]<0,则说明 t 包含一个不在 s 中的额外字符,返回 false 即可。
func isAnagram(s, t string) bool {
var c1, c2 [26]int
for _, ch := range s {
c1[ch-'a']++
}
for _, ch := range t {
c2[ch-'a']++
}
return c1 == c2
}
对于进阶问题,Unicode 是为了解决传统字符编码的局限性而产生的方案,它为每个语言中的字符规定了一个唯一的二进制编码。而 Unicode 中可能存在一个字符对应多个字节的问题,为了让计算机知道多少字节表示一个字符,面向传输的编码方式的UTF−8 和 UTF−16 也随之诞生逐渐广泛使用,具体相关的知识读者可以继续查阅相关资料拓展视野,这里不再展开。
回到本题,进阶问题的核心点在于「字符是离散未知的」,因此我们用哈希表维护对应字符的频次即可。同时读者需要注意Unicode 一个字符可能对应多个字节的问题,不同语言对于字符串读取处理的方式是不同的。
func isAnagram(s, t string) bool {
if len(s) != len(t) {
return false
}
cnt := map[rune]int{}
for _, ch := range s {
cnt[ch]++
}
for _, ch := range t {
cnt[ch]--
if cnt[ch] < 0 {
return false
}
}
return true
}