567. Permutation in String Medium

来源:互联网 发布:淘宝刷手会被坐牢吗 编辑:程序博客网 时间:2024/05/19 00:10

这是需要记得的一道题,虽然不难,用的方法很典型。类别是Two Pointers。

主要思想是Slide Window,从头开始对于长度等于S1的子串,判断是不是S1的一个排列。


这里我们需要考虑的一个子问题是,对于两个长度相同的字符串,怎么样判断它们是不是同一些字符的不同排列呢?当然你也可以排序,但是会很慢。这里用一个比较典型的方法,因为题目中规定只能出现小写字母,我们可以用一个长度为26的int数组来记录字符串中每一个字母出现的次数。那么对于这个子问题,我们可以同时遍历这两个字符串,在s1中出现的字符,我们在数组对应位置+1,在s2中出现的字符,我们在对应位置-1,这样,在遍历结束后,如果这两个字符串是同一些字符的不同排列,则数组应该全部为0。用这种巧妙的方法,我们就避免了排序,而且速度很快。


现在我们把这个方法用到这道题中。先在s2的开头,取跟s1长度一样的字符串,判断跟s1是不是同一排列,如果是当然好了。如果不是,我们开始滑动窗口,向右滑一个字符。注意此时的int数组, 肯定不全为0,它现在表示的意思可以理解为当前子串与s1之间的“相对差距”。这里又有一个巧妙的想法。此时对于这个新的子串,我们还需要按上面的方法跟s1比较吗?不需要!我们只需要继续维护那个int数组就可以了。对于新加入的字符,我们要在数组的对应位置减一(在s2中出现的都-1,在s1中出现的都+1),别忘了给因为滑动而去掉的第一个字符在对应位置加一!这样我们一直记录着s1与子串之间的相对差距,直到数组全为0(写个函数判断),说明它们是同一个排列,则应该返回true。如果到窗口右边滑到最后还没有结果,就是false。


class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        if(s1.size() > s2.size())return false;
        int calc[26] = {0};
        for (int i = 0; i < s1.size(); ++i)
        {
        calc[s1[i] - 'a']++; //calculate the char in s1
        calc[s2[i] - 'a']--; //calculate the char in s2
        }
        //calc is the relative distance of s1 and head of s2
        //calc is 0 => s1 == head of s2
        if(allZero(calc))return true;


        //slide window
        for (int i = s1.size(); i < s2.size(); ++i)
        {
        //restore the first char
        calc[s2[i - s1.size()] - 'a']++;
        //add new char
        calc[s2[i] - 'a']--;
        if(allZero(calc))return true;
        }
        return false;
    }
    bool allZero(int * a)
    {
    for (int i = 0; i < 26; ++i)
    if(a[i] != 0)return false;
    return true;
    }
};

0 0
原创粉丝点击