Leetcode - 567 Permutation in String
Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string.
Example 1:
Input:s1 = "ab" s2 = "eidbaooo"
Output:True
Explanation: s2 contains one permutation of s1 ("ba").
Input:s1 = "ab" s2 = "eidbaooo"
Output:True
Explanation: s2 contains one permutation of s1 ("ba").
Example 2:
Input:s1= "ab" s2 = "eidboaoo"
Output: False
Output: False
观察一下此题的解空间,实际上是要在目标字符串中寻找一个子串,该子串与模式串的某一个排列相同。基于这点,容易想到是否能用双指针的算法来求解。
即,用前后指针扫描整个目标串,在扫描的过程中始终维护一个记录扫描的子串中各字符出现次数的哈希表c,并不断将该哈希表与h进行比较,根据比较结果对前后指针进行操作,直至完成整个目标串的扫描。
整个扫描过程中的不变条件为:前后指针所控制区域形成的子串始终是目标串集合的子集。
具体操作方法如下:
- 预处理:扫描模式串,将模式串中每个字符的出现次数记录在一个哈希表h中。
- 主逻辑:扫描目标串,在扫描的过程中始终维护一个记录扫描的子串中各字符出现次数的哈希表c。
- 若前指针所指字符不属于模式串,说明该字符并非所需。为了保证不变条件始终成立,必须将当前子串清空,即后指针指向前指针,清空c。然后前指针向前继续扫描。
- 若前指针所指字符虽属于模式串,但是它在c中的出现次数已然等于模式串中的次数。这种情况说明我们需要压缩当前子串,使不变条件始终成立。比如:模式串为aaabc,当前扫描子串为baaaa。扫描至当前字符a(最后一个a),子串中a的数量已经高于模式串中a的数量。在这种情况下,我们必须将后指针不断向前移动,直到遇到a。对于此例,即aaa。压缩完毕之后,前指针继续向前扫描。
- 若前指针所指字符属于模式串,且它在c中的出现次数小于模式串中的次数。说明这个字符是我们需要的,将它在c中的出现次数加一。此时判断当前子串的长度,若与模式串相同,说明当前子串已经满足条件,返回true退出。否则,前指针继续向前扫描。
上代码:
bool checkInclusion(string s1, string s2) { unordered_map<char, int> pat; for (int i = 0; i < s1.length(); i++) { pat[s1[i]]++; } int f = 0; int b = 0; unordered_map<char, int> cur; while (f < s2.length()) { if (pat[s2[f]] > 0 && cur[s2[f]] < pat[s2[f]]) { // this char is accepted cur[s2[f]]++; // check all string match or not? if (f - b + 1 == s1.length()) return true; else f++; } else if (pat[s2[f]] > 0 && cur[s2[f]] == pat[s2[f]]) { // redundant char. Increment b. do { cur[s2[b]]--; b++; } while (s2[f] != s2[b-1]); } else { // mismatch char. make b equal f. f++; b = f; cur.clear(); } } return false; }