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

1、题目描述

2、题目解析

 题目中出现了一个名词,【异位词】异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

此题可以用经典的【滑动窗口解法】,从网上找到了一个大神(labuladong)的打油诗:

可以参考滑动窗口共用模板进行代码实现完善,公共模板参考之前梳理文章,链接如下:

算法分享系列--滑动窗口问题 

【滑动窗口】子串问题全靠它。左右指针滑窗口。此类算法的模板代码显示如下:

int left = 0, right = 0;

while (right < s.size()) {
    // 增大窗口
    window.add(s[right]);
    right++;
    
    while (window needs shrink) {
        // 缩小窗口
        window.remove(s[left]);
        left++;
    }
}

真的是怒赞暴力推荐大神lubuladong 的这套全解析【简直是神操作】:力扣https://leetcode.cn/problems/find-all-anagrams-in-a-string/solution/hua-dong-chuang-kou-tong-yong-si-xiang-jie-jue-zi-/

从而相关的一系列题目都迎刃而解了

76.最小覆盖子串

567.字符串的排列

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

3.无重复字符的最长子串

自梳理的代码实现【JAVA版】

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
         Map<Character,Integer> need = new HashMap<Character,Integer>();
         Map<Character,Integer> window = new HashMap<Character,Integer>();
         for(char c : p.toCharArray()){
            if(need.containsKey(c)){
                need.put(c,need.get(c)+1);
            }else{
                need.put(c,1);
            }
         }

         int left = 0; 
         int right = 0; 
         int valid = 0;

         List<Integer> res = new ArrayList<Integer>();
         while(right < s.length()){
             char c = s.charAt(right);
             //滑动窗口右移
             right++;
             if(window.containsKey(c)){
                 window.put(c, window.get(c)+1);
             }else{
                 window.put(c, 1);
             }
             //如果两个map中该元素个数一致,则有效数据增加
             if(window.get(c).equals(need.get(c)))
                  valid++;
             
              //判断左侧窗口是否要收缩,这样限制了(right-left)的区间长度
              while((right-left) >= p.length()){
                   if(valid == need.size()){
                       res.add(left);
                   }
                   //滑动窗口进行收缩
                   char d = s.charAt(left);
                   left++;
                   if(need.containsKey(d)){
                       if(window.get(d).equals(need.get(d)))
                              valid--;
                       window.put(d,window.get(d)-1);
                   }    
              }
         }
         return res;
    }
}

复杂度分析

时间复杂度:最坏情况下左右指针对 s 的每个元素各遍历一遍,哈希表中对 s 中的每个元素各插入、删除一次,对 p 中的元素各插入一次。每次检查是否可行会遍历整个 p 的哈希表,哈希表的大小与字符集的大小有关,则渐进时间复杂度为 O(∣s∣+∣p∣)。


空间复杂度:这里用了两张哈希表作为辅助空间,每张哈希表最多不会存放超过字符集大小的键值对,我们设字符集大小都不会超过字符串本身 ,则渐进空间复杂度为 O(∣s∣+∣p∣)。
 

解题特点:

       比较字符出现次数时,window.get(d).equals(need.get(d))  ,之前写成   window.get(d) == (need.get(d)) 对于长字符就会出错,Integer 在大于127 的时候是【对象】,因此不能使用数字模式进行比较了!
 

可以使用滑动窗口和哈希表来解决这个问题。具体步骤如下: 1. 定义一个哈希表,用于记录目标字符串每个字符出现的次数。 2. 定义两个指针 left 和 right,分别表示滑动窗口的左右边界。 3. 初始化 left 和 right 为 0,表示滑动窗口的大小为 0。 4. 遍历目标字符串,每次将 right 指针向右移动一格,并将对应的字符出现次数加一。 5. 如果 right - left == p.length(),说明滑动窗口的大小已经达到了目标字符串 p 的长度,此时需要判断滑动窗口的字符是否是 p 的一个字母异位。 6. 判断方法是比较滑动窗口的字符出现次数和 p 每个字符出现次数是否一致,如果一致则说明找到了一个字母异位。 7. 将 left 指针向右移动一格,同时将对应的字符出现次数减一,继续遍历目标字符串Java 代码实现如下: ``` public List<Integer> findAnagrams(String s, String p) { List<Integer> result = new ArrayList<>(); if (s == null || s.length() == 0 || p == null || p.length() == 0) { return result; } int[] hash = new int[26]; for (char c : p.toCharArray()) { hash[c - 'a']++; } int left = 0, right = 0, count = p.length(); while (right < s.length()) { if (hash[s.charAt(right) - 'a'] > 0) { count--; } hash[s.charAt(right) - 'a']--; right++; if (count == 0) { result.add(left); } if (right - left == p.length()) { if (hash[s.charAt(left) - 'a'] >= 0) { count++; } hash[s.charAt(left) - 'a']++; left++; } } return result; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值