思路:滑动窗口(双指针)
- 可以常规滑动窗口做,比较简单,但是空间成本比较大。
 - 维护一个账本
debt[26],账本里面的26个项目对应26个字母 - s1中的所有账目都是欠的钱
 ++debt[s2[right] -'a'],right指向的位置可以还钱,但是如果多还了,就要一直右移左指针,直到没有多还为止(确保left到right范围内的字母都在s1中),如果长度和s1相同,那么就是子字符串。
代码:
class Solution {public:    bool checkInclusion(string s1, string s2) {        // s1可以看成一个欠账本,里面一共有26项        // s2可以看成一个还钱的账本,也是一共26项        vector<int> debt(26, 0);        int len_s1 = s1.size(), len_s2 = s2.size();        for (int i = 0; i < len_s1; ++i) {            debt[s1[i] - 'a']--;        }        for (int left = 0, right = 0; right < len_s2; ++right) {            // right 所在的位置是还钱的            ++debt[s2[right] - 'a'];            while (debt[s2[right] - 'a'] > 0) {                // 如果多还了钱,那么要把之前多还的欠回去                // 确保left - right范围内都是s1中出现过的                --debt[s2[left++] - 'a'];            }            // 如果已经还的钱的数量,和一开始欠的数量相同,那么就存在子字符串            if (right - left + 1 == len_s1) {                return true;            }        }        return false;    }};