567. 字符串的排列

1、题目描述

 2、题目解析

参照【滑动窗口】通用解题模板,直接套用即可,

对应我之前总结的链接为:算法分享系列--滑动窗口问题

以下是【JAVA】实现的完整版本:

class Solution {
    //【滑动窗口】经典类题目,s2是否包含s1的序列
    public boolean checkInclusion(String s1, String s2) {
        Map<Character,Integer> need = new HashMap<Character,Integer>();
        Map<Character,Integer> window = new HashMap<Character,Integer>();
        for(char c : s1.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;
        while(right < s2.length()){
           char c = s2.charAt(right);
           //滑动窗口右移
           right++;
           if(window.containsKey(c)){
              window.put(c, window.get(c)+1);
           }else{
              window.put(c, 1);
           }
          
           //如果该右边字符是need中包含字符,则进行相关校验
           if(need.containsKey(c)){
              // 【注意】这里进行比较要用 equals,不用 == 
              // 因为 Integer 在大于127 的时候 不从常量池里拿,是个对象
              if(need.get(c).equals(window.get(c))){
                   valid++;
              }
           }

           //判断左侧窗口是否需要收紧,此时就是时刻以【right-left】的长度进行校验
           while( right-left >= s1.length()){
               // 在这里判断是否找到了合法的子串
               if(valid == need.size()){
                   return true;
               }
               //进行左边窗口缩紧
               char d = s2.charAt(left);
               left++;
               if(need.containsKey(d)){
                   if(need.get(d).equals(window.get(d))){
                       valid--;
                   }              
               }
               window.put(d, window.get(d)-1);
           }
           
        }
        // 未找到符合条件的子串
        return false;
    
    }
}

复杂度分析

时间复杂度:最坏情况下左右指针对 【s2】 的每个元素各遍历一遍,哈希表中对 【s2】 中的每个元素各插入、删除一次,对 【s1】 中的元素各插入一次。每次检查是否可行会遍历整个 【s1】 的哈希表,哈希表的大小与字符集的大小有关,则渐进时间复杂度为 O(∣s1∣+∣s2∣)。
空间复杂度:这里用了两张哈希表作为辅助空间,每张哈希表最多不会存放超过字符集大小的键值对,我们设字符集大小都不会超过字符串本身 ,则渐进空间复杂度为 O(∣s1∣+∣s2∣)。

备注:

1、代码中需要注意部分,均已经用注释备注完毕

2、 比如这里一定 要使用 equals, 而不使用 == 

              // 【注意】这里进行比较要用 equals,不用 == 
              // 因为 Integer 在大于127 的时候 不从常量池里拿,是个对象
              if(need.get(c).equals(window.get(c))){

3、本题移动 left 缩小窗口的时机是窗口大小大于s1.length()  时,应为排列嘛,显然长度应该是一样的。对应代码如下。

         //判断左侧窗口是否需要收紧,此时就是时刻以【right-left】的长度进行校验
          while( right-left >= s1.length()){

4、当发现 valid == need.size() 时,就说明窗口中就是一个合法的排列,所以立即返回 true。

至于如何处理窗口的扩大和缩小,和最小覆盖子串完全相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值