剑指 Offer II 014. 字符串中的变位词
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。
换句话说,第一个字符串的排列之一是第二个字符串的 子串 。
示例 1:
输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
示例 2:
输入: s1= "ab" s2 = "eidboaoo"
输出: False
提示:
1 <= s1.length, s2.length <= 104
s1 和 s2 仅包含小写字母
解析1:
对s2使用一个长度为s1.length()的滑动窗口
class Solution { public: bool checkInclusion(string s1, string s2) { vector<int> vis1(26, 0), vis2(26, 0); int n = s1.length(); int m = s2.length(); if(n > m) return false; for(int i = 0; i < n; i++) { vis1[s1[i] - 'a']++; vis2[s2[i] - 'a']++; } if(vis1 == vis2) return true; for(int i = n; i < m; i++) { vis2[s2[i - n] - 'a']--; vis2[s2[i] - 'a']++; if(vis1 == vis2) return true; } return false; } };
解析2:
vis记录s1中每个字母出现的次数
遍历s2,如果遇到一个s1中的字母temp,vis1[temp]++,即vis1用来记录当前所遇到的s1中相应字母的个数
如果vis1[temp] >= vis[temp],说明当前位置i的字母出现多了,那么就删去第一次出现的temp
试想 如果删去了第一次出现的temp,那么这个连续子串就中断了,所以从这个连续子串开始的位置到第一次出现temp的位置的字母都要删去
更新子串开始位置为第一次出现temp位置的下一个位置
二维queue记录每个字母的出现位置
删去的时候,相应的queue pop就可以,即更新每个字母第一次出现的位置
class Solution { public: bool checkInclusion(string s1, string s2) { int vis[30], vis1[30]; memset(vis, 0, sizeof(vis)); queue<int> q[30]; memset(vis1, 0, sizeof(vis1)); int len1 = s1.length(); for(int i = 0; i < len1; i++) { vis[s1[i] - 'a']++; } int ans = len1, cnt = 0, len2 = s2.length(), start; for(int i = 0; i < len2; i++) { if(cnt == ans) { return true; } int temp = s2[i] - 'a'; if(vis[temp]) { if(vis1[temp] >= vis[temp]) { int ll = q[temp].front(); for(int j = start; j <= ll; j++) vis1[s2[j] - 'a']--, cnt--, q[s2[j] - 'a'].pop(); start = ll + 1; } if(cnt == 0) start = i; vis1[temp]++, cnt++; q[temp].push(i); } else { for(int j = 0; j < 30; j++) while(!q[j].empty()) q[j].pop(); memset(vis1, 0, sizeof(vis1)); cnt = 0; } } return cnt == ans ? true : false; } };
自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。