滑动窗口问题 基本上就是 判断某个字符串P是否在其他字符串S里面出现过.
指针法+hash,具体思路是 用hash存取p节点的value-index值(这样方便查找O(1)),然后就是特别注意左指针是在啥时候移动的,这题由于滑动窗口大小固定了,因此判断条件为 right-left>=p.size()。 题目leetcode 76.最小覆盖子串这题由于没有固定滑动窗口大小,因此只能是判断是否valid==need.size(),如果符合,将左指针右移。
438. 找到字符串中所有字母异位词 给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。 不考虑答案输出的顺序。 示例 1:
输入: s: “cbaebabacd” p: “abc”
输出: [0, 6]
解释: 起始索引等于 0 的子串是 “cba”, 它是 “abc” 的字母异位词。 起始索引等于 6 的子串是 “bac”, 它是 “abc” 的字母异位词。 示例 2:
输入: s: “abab” p: “ab”
输出: [0, 1, 2]
解释: 起始索引等于 0 的子串是 “ab”, 它是 “ab” 的字母异位词。 起始索引等于 1 的子串是 “ba”, 它是 “ab” 的字母异位词。 起始索引等于 2 的子串是 “ab”, 它是 “ab” 的字母异位词。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 代码:
class Solution { public: vector<int> findAnagrams(string s, string p) { unordered_map<char,int> need,window; for(char c:p) { need[c]++; } //双指针 int left=0,right=0; int valid=0; vector<int> ret_v; while(right<s.size()) { char c=s[right]; right++; if(need.count(c)) { window[c]++; if(window[c]==need[c]) { valid++; } } //左指针开始向右移动 while(right-left>=p.size()) { if(valid==need.size()) { ret_v.push_back(left); } char d=s[left]; left++; if(need.count(d)) { if(window[d]==need[d]) { valid--; } window[d]--; } } } return ret_v; } };76. 最小覆盖子串 给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入:S = “ADOBECODEBANC”, T = “ABC” 输出:“BANC”
提示:
如果 S 中不存这样的子串,则返回空字符串 “”。 如果 S 中存在这样的子串,我们保证它是唯一的答案。
思路: 注意左指针移动条件,因为窗口没有固定,指针移动条件为valid==need.size() ==》 满足移动
class Solution { public: string minWindow(string s, string t) { unordered_map<char,int> need,window; for(char c:t) { need[c]++; } int left=0,right=0; int valid=0;//一般来说 valid=t.size() 就能够到达条件了 //下面这两个变量是根据中求最短的路径,我们需要求的 int start=0; int len=INT_MAX; while(right<s.size()) { char c=s[right]; //cout<<"c="<<c<<endl; right++;//这两句连在一起写,也就是现使用然后再加一 if(need.count(c)) { window[c]++; if(window[c]==need[c])//这就是代表滑动窗口中有有某个元素1已经符合条件了 { valid++; } } //窗口指针左移 while(valid==need.size())//条件。这点很重要,不同的题目可能只有这里改一下就基本可以了 { cout<<"进来了"; if(right-left<len) { start=left; len=right-left; } char d=s[left]; left++; if(need.count(d))//左结点出现了在need中的值 { if(window[d]==need[d]) { valid--; } window[d]--; } } } return len==INT_MAX ? "":s.substr(start,len); } };567. 字符串的排列 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo” 输出: True 解释: s2 包含 s1 的排列之一 (“ba”).
示例2:
输入: s1= “ab” s2 = “eidboaoo” 输出: False
思路 注意左指针移动条件,因为窗口固定,指针移动条件为right-left==s1.size() ==》 满足移动
代码:
class Solution { public: bool checkInclusion(string s1, string s2) { //滑动窗口 unordered_map<char,int> need,window; for(char c: s1) { need[c]++; } int left=0, right=0; int valid=0; while(right<s2.size()) { char c=s2[right]; right++;//先使用,将指针向后移动 if(need.count(c)) { window[c]++; if(window[c]==need[c]) { valid++; } } //移动滑动窗口 while(right-left>=s1.size())//我们需要将左指针右移 我们需要注意 right已经指向下一个元素了 { if(valid==need.size()) { return true; } char d=s2[left]; left++; if(need.count(d)) { if(window[d]==need[d]) { valid--; } window[d]--; } } } return false; } };