【算法】字符串的排列

131 阅读1分钟

题目

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。 换句话说,s1 的排列之一是 s2 的 子串 。 (s1 和 s2 仅包含小写字母

解题思路

关键点

  • 一般遇到仅包含字母的题目时就能有特定解法
  • 利用ASCII编码 减去'a',即可获得对应的差值(ASCII),差值为0就是a,1就是b(26个字母)
  • Arrays.equals: 对比两个数组是否相等

思路分析

  • 定义一个26字母的字母表数组来存储个数
  • 如果字符串s1 是 s2 的一个排列,只要相同长度内,各个字符的数目一样,就可以排列成功。
  • 依据上述规则以s1字符串长度一样的窗口在s2上做移动操作。
  • 窗口从左向右移动,每次移动并从s2字符串中移除最右边字符并在数组中减去1,添加左边新加入字符并在数组中加1。

代码

窗口移动

class Solution {
    public boolean checkInclusion(String s1, String s2) {
            int length1 = s1.getLength();
            int length2 = s2.getLength();
            if(length1 > length2) return false;
            int[] s1Char = new int[26];
            int[] s2Char = new int[26];
            for(int i = 0; i< length1;i++){
                s1Char[s1.charAt(i) - 'a']--;
                s2Char[s2.charAt(i) - 'a']--;
            }
            if(Arrays.equals(s1,s2)) return true;
            for(int i = length1; i < length2;i++){
                s2Char[s2.charAt(i - length1) - 'a']--;
                s2Char[s2.charAt(i) - 'a']++;
                if(Arrays.equals(s1,s2)) return true;
            }
            return false;
            // int left = 0;
            // for(int r = 0;r < length2;r++){
            //     int count = s2.charAt(r) - 'a';
            //     s1Char[count] ++;
            //     while(s1Char[count] > 0){
                    
            //     }
            // }
    }
}

进阶窗口移动

class Solution {
    public boolean checkInclusion(String s1, String s2) {
            int length1 = s1.length();
            int length2 = s2.length();
            if(length1 > length2) return false; // 意外情况排除
            int[] s1Char = new int[26]; // 记录s1中每个字母数量
            for(int i = 0; i< length1;i++){
                s1Char[s1.charAt(i) - 'a']--;
            }
            int left = 0;
            for(int r = 0;r < length2;r++){ // 遍历长数组
                int count = s2.charAt(r) - 'a';
                s1Char[count] ++; // 抵消短数组中的计数值
                while(s1Char[count] > 0){ // 如果计数字母大于0 就表明当前s1窗口和s2不吻合
                    // 不吻合的情况下就要移动窗口 (起始在下标0 右移s1 
                    // 减去最左边一个字母
                    s1Char[s2.charAt(left) - 'a']--;
                    left++;
                }
                if (r - left + 1 == length1){    //若左右指针间长度等于s1的长度
                    return true;             
                }
            }
            return false;
    }
}

来源