LeetCode 567 Permutation in String

解法

统计s1中字符出现次数countOfLetters,使用双指针,维护s2中双指针之间的字符的出现次数tmpCountOfLetters以及s1中未被访问到的字符数countLeft。对于双指针i,j,后者用来考察在s1中出现的字符,前者用来将不满足的字符剔除考察范围。

j指针前移过程:

若 s2[j] 在 s1 中出现过,且当前出现次数小于s1中出现次数
    将 j 处字符的当前出现次数加一 tmpCntOfLetters[s2[j]]++
    未被访问字符数减一  cntLeft--
    j前移
    继续循环

i指针前移

若 s2[j] 未在 s1 中出现过
    将 i 向前移动到 j 的位置
        移动时将 i 处字符出现次数减一  tmpCntOfLetters[s2[i]]--
        将 s1 中未被访问的字符数加一   cntLeft++
否则,若 s2[j] 在 s1 中出现过,但当前出现次数大于 s1 中次数
    将 i 前移一位,同样更新 tmpCntOfLetters 和 countLeft

其中比较关键的点:

  1. 若j遇到未在s1中出现过的字符,i和j都前移到j+1

    j之前不可能出现满足条件的(会直接终止),且j处字符一定不会在所求区间内(未在s1出现)

  2. 若j遇到在s1中出现但超过出现次数的字符,i前移1,此后继续考察j位置的字符

    因为i处的字符必定是在s1中出现过的,所以需要慎重将其从考察范围内剔除

  3. i前移过程不会出现条件满足的情况,假设出现了满足条件的,那么一定会在该情况处立即终止

代码

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        if (s1.size() > s2.size())
            return false;
        int cntOfLetters[26] = {};
        for (auto &&ch : s1)
            cntOfLetters[ch - 'a']++;
        int tmpCntOfLetters[26] = {};
        int cntLeft = (int)s1.size();
        int i = 0, j = 0;

        while (j < (int)s2.size()) {
            while (j < (int)s2.size() && tmpCntOfLetters[s2[j] - 'a'] < cntOfLetters[s2[j] - 'a']) {
                tmpCntOfLetters[s2[j] - 'a']++;
                cntLeft--;
                j++;
            }
            if (cntLeft == 0)
                return true;
            if (j == (int)s2.size())
                return false;
            if (cntOfLetters[s2[j] - 'a'] == 0) { // move i here
                while (i <= j) {
                    if (tmpCntOfLetters[s2[i] - 'a'] > 0) {
                        tmpCntOfLetters[s2[i] - 'a']--;
                        cntLeft++;
                    }
                    i++;
                }
                j++;
            } else { //
                tmpCntOfLetters[s2[i] - 'a']--;
                cntLeft++;
                i++;
            }
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值