242. 有效的字母异位词(排序后用Map或者滑动窗口用Map)

242. 有效的字母异位词

242. 有效的字母异位词

给定两个字符串 st,编写一个函数来判断t是否是s
字母异位词(字母异位词是通过重新排列不同单词或短语的字母而形成的单词或短语,并使用所有原字母一次。)

示例 1:

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

示例 2:

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

提示:

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

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

哈希表思路:

数组有时候也可以充当Map使用

什么时候用哈希表

  • 一般来说哈希表都是用来快速判断一个元素是否出现集合里。

什么时候用数组

  • 当题目明确指出只有字符串的时候,可以使用数组存储ascii码

当前题目由于都是小写字母,而字母就26个,故可以建立一个长度是26的数组,遍历sts中某个字母出现了就将他对应的数组中那个位置加1,而t相反,是减1,最后判断数组中每个元素是否为0即可

因为字符a到字符zASCII26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25

在遍历 字符串s的时候,只需要将s[i] - ‘a’所在的元素做+1 操作即可,并不需要记住字符aASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了。

那看一下如何检查字符串t中是否出现了这些字符,同样在遍历字符串t的时候,对t中出现的字符映射哈希表索引上的数值再做-1的操作。

那么最后检查一下,arr数组如果有的元素不为零0,说明字符串st一定是谁多了字符或者谁少了字符,return false

最后如果record数组所有元素都为零0,说明字符串s和t是字母异位词,return true。

Go代码

func isAnagram(s string, t string) bool {
    /*思路:字母异位词即两个单词中相同字母出现相同次数
    由于都是小写字母,而字母就26个,故可以建立一个长度是26的数组
    遍历s和t,s中某个字母出现了就将他对应的数组中那个位置加1,
    而t相反,是减1,最后判断数组中每个元素是否为0即可*/
    if len(s) != len(t) {
        return false
    }

    arr := make([]int,26)
    for i := 0;i < len(s);i++{
        a := s[i] - 'a'
        b := t[i] - 'a'
        arr[a]++
        arr[b]--
    }
    
    for i := 0;i < len(arr);i++ {
        if arr[i] != 0 {
            return false
        }
    }

    return true
}

在这里插入图片描述

49. 字母异位词分组

49. 字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

示例 2:

输入: strs = [""]
输出: [[""]]

示例 3:

输入: strs = ["a"]
输出: [["a"]]
 

提示:

  • 1 <= strs.length <= 10^4
  • 0 <= strs[i].length <= 100
  • strs[i] 仅包含小写字母

Go代码

func groupAnagrams(strs []string) [][]string {
    //我们可以用一个map[string][]string来完成分组,其中key是单词按字母序排序后的形式,
    //value则是所有按字母序排序后是key的单词的集合,由此即完成了分组的任务。
    if len(strs) == 0 {
        return [][]string{}
    }

    m := make(map[string][]string)
    for i := 0;i < len(strs);i++ {
        // sort只提供了对切片的排序,所以先转为字节切片,后面再转回字符串
        temp := []byte(strs[i])
        sort.Slice(temp,func(i,j int)bool {return temp[i] < temp[j]})
        key:= string(temp)
        
        if _,ok := m[key];ok {
            m[key] = append(m[key],strs[i])
        } else {
            arr := make([]string,0)
            arr = append(arr,strs[i])
            m[key] = arr
        }
    }

    res := make([][]string,0)
    for _,val := range m {
        res = append(res,val)
    }

    return res
}

在这里插入图片描述

438. 找到字符串中所有字母异位词

438. 找到字符串中所有字母异位词

给定两个字符串 sp,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

提示:

  • 1 <= s.length, p.length <= 3 * 10^4
  • s 和 p 仅包含小写字母

思路:

暴力法: 异位词排序之后的字符串是相等的,所以可以以s的每一个字符作为起点,取和p相同长度的字符,看看排序后是否相等即可。注:该方法主要是提供了一下思路,在leetcode上提交的时候会超时。

Go代码

func findAnagrams(s string, p string) []int {
    // 异位词排序之后的字符串是相等的
    // 所以可以以s的每一个字符作为起点,取和p相同长度的字符,看看排序后是否相等即可

    if len(s) == 0 || len(s) < len(p){
        return []int{}
    }

    var res []int
    // 注意:因为最后一个字符串长度至少需要len(p)
    // 所以遍历的最后一个位置应该是 len(s) - len(p),因此这里是小于 len(s) - len(p) + 1
    for i := 0;i < len(s) - len(p) + 1;i++ {
        if sortString(s[i:i+len(p)]) == sortString(p) {
            res = append(res,i)
        }
    }
    
    return res
}

// 将字符串s排序后返回新的字符串
func sortString(s string) string {
    temp := []byte(s)
    sort.Slice(temp,func(i,j int)bool {return temp[i] < temp[j]})
    return string(temp)
}

在这里插入图片描述

滑动窗口法:滑动窗口法:异位词的每个字母出现的次数都是一样的,滑动窗口四步走,如下:

  1. 窗口内容:当前窗口长度与p相同
  2. 如果移动终点:后移直到窗口长度与p相同
  3. 如何移动起点:后移直到窗口长度与p相同
  4. 结果:当前窗口内容是否是p的异位词,即每个字符出现次数相同,符合条件则加到结果中。

Go代码

func findAnagrams(s string, p string) []int {
    // 滑动窗口法:异位词的每个字母出现的次数都是一样的
    /*
    1. 窗口内容:当前窗口长度与p相同
    2. 如果移动终点:窗口长度与p相同
    3. 如何移动起点:窗口长度与p相同
    4. 结果:当前窗口内容是否是p的异位词,即每个字符出现次数相同
    */
    if len(s) == 0 || len(s) < len(p) {
        return []int{}
    }

    res := make([]int,0)
    // p 中每个字符出现的次数
    mp := make(map[byte]int)
    for i := 0;i < len(p);i++ {
       mp[p[i]]++ 
    }

    ms := make(map[byte]int) // 记录当前窗口每个字符出现的次数
    left,right := 0,0
    for ;right < len(s);right++ {
        ms[s[right]]++ // 当前字符出现次数加1
        if right - left + 1 < len(p) {
            continue
        }

        // 窗口长度和p相等时,比较每个字符出现的次数是否也相等
        flag := true // 默认当前窗口和p是异位词
        for k,v := range mp {
            if cnt,ok := ms[k];!ok || cnt != v {
                flag = false
                break
            } 
        }
        
        if flag {
            res = append(res,left)
        }
        // 起点后移
        ms[s[left]]--
        left++       
    }

    return res
    
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值