leetcode:567. 字符串的排列
题目
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。
示例:
输入:s1 = "ab" s2 = "eidbaooo"输出:true解释:s2 包含 s1 的排列之一 ("ba").
输入:s1= "ab" s2 = "eidboaoo"输出:false
解答 & 代码
滑动窗口写法一
滑动窗口,思路同:
[困难] 76. 最小覆盖子串
只有两点区别:
- 窗口左侧收缩的时机,变为窗口大小 >=
s1长度时。因为窗口要满足条件,就得是s1的一个排列,长度就应该等于s1。右边界扩张到窗口大小 >=s1长度时,如果不收缩下左边界,右边界继续扩张,窗口继续变大,不可能满足条件 在收缩窗口时判定是否找到了合法的窗口,即
validChCnt == needs.size()(此时等长,且包含字符相同,所以窗口是s1的一个排列)class Solution {public:bool checkInclusion(string s1, string s2) {unordered_map<char, int> needs;unordered_map<char, int> window;for(int i = 0; i < s1.size(); ++i)++needs[s1[i]];int left = 0;int right = 0;int validChCnt = 0;while(right < s2.size()){char c = s2[right];++right;if(needs.find(c) != needs.end()){++window[c];if(window[c] == needs[c])++validChCnt;}// 变化 1:窗口左侧收缩的时机,变为窗口大小 >= s1 长度时// 因为窗口要满足条件,就得是 s1 的一个排列,长度就应该等于 s1while(right - left >= s1.size()){// 变化 2:判断是否找到了合法的窗口if(validChCnt == needs.size())return true;char deleteC = s2[left];++left;if(needs.find(deleteC) != needs.end()){if(window[deleteC] == needs[deleteC])--validChCnt;--window[deleteC];}}}return false;}};
复杂度分析:设字符串
s2长为 N,字符串s1包含 C 个不同的字符
- 时间复杂度 O(N):最坏情况下,字符串
s2的每个字符分别被左、右指针遍历一次 - 空间复杂度 O(C):两个哈希表的空间复杂度都取决于字符串
s1中不同字符的种数 C
执行结果:
执行结果:通过执行用时:12 ms, 在所有 C++ 提交中击败了 42.60% 的用户内存消耗:7.3 MB, 在所有 C++ 提交中击败了 25.09% 的用户
滑动窗口写法二 [推荐]
上面的写法改变了窗口收缩时机。
下面的写法更加模板化,窗口收缩时机不变,唯一的改变就是判定窗口是否合法
class Solution {public:bool checkInclusion(string s1, string s2) {unordered_map<char, int> need;unordered_map<char, int> window;for(int i = 0; i < s1.size(); ++i)++need[s1[i]];int left = 0;int right = 0;int validCnt = 0;while(right < s2.size()){char ch = s2[right];++right;if(need.find(ch) != need.end()){++window[ch];if(window[ch] == need[ch])++validCnt;}// 窗口收缩(左边界右移)while(validCnt == need.size()){// 唯一的变化:在这里判断是否找到了合法的窗口,即窗口长度 == s1 的长度if(right - left == s1.size())return true;char deleteCh = s2[left];++left;if(need.find(deleteCh) != need.end()){--window[deleteCh];if(window[deleteCh] == need[deleteCh] - 1)--validCnt;}}}return false;}};
执行结果:
执行结果:通过执行用时:24 ms, 在所有 C++ 提交中击败了 14.64% 的用户内存消耗:7.1 MB, 在所有 C++ 提交中击败了 71.42% 的用户
