[LeetCode-438][找到字符串中所有字母异位词][Find All Anagrams in a String]
原题
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string
【中文】
给定一个字符串 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" 的字母异位词。【英文】
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.
Example 1:
Input:
s: "cbaebabacd" p: "abc"
Output:
[0, 6]
Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
Example 2:
Input:
s: "abab" p: "ab"
Output:
[0, 1, 2]
Explanation:
The substring with start index = 0 is "ab", which is an anagram of "ab".
The substring with start index = 1 is "ba", which is an anagram of "ab".
The substring with start index = 2 is "ab", which is an anagram of "ab".
题解思路:
题目中是对目标子串p的各种组合的查找,即在字符串s中查找子串中的字符均在p中,且出现次数与目标子串p中的次数即可。采用滑动窗口方法,具体如下。
- 首先,建立目标子串的标记数组mark[],用于标记字符串p中各字母出现的次数。
- 其次,从字符串s的位置0开始向后建立滑动窗口,以匹配字符串p中字母均有出现的情况。
- 将窗口右位置r处的字母mark-1,展开窗口。
- 若mark[s[r]]>=0,则r处字母在目标子串p中,已匹配字符的长度len增加1.
- 窗口向右移动。窗口左位置l,右位置r,窗口长度(r-l+1), 目标匹配字符串p的长度pLen。当窗口长度(r-l+1) > pLen时,将窗口向右移动。
- 将窗口左位置l的字母mark恢复+1,
- 若mark[s[l]] > 0,则表示该字母在目标子串中,需要将已匹配长度len减小1;否则,mark[s[l]]会为0;
- 窗口左位置l++,窗口完成右移。
- 确认已找到符合要求的子串。当已匹配的字符串长度len和目标子串p长度相等,则表明已找到一个符合要求的子串。
代码:
1 /** 2 * Note: The returned array must be malloced, assume caller calls free(). 3 */ 4 #define MARK_SIZE (256) 5 #define MAX_STRING_SIZE (20100) 6 7 int* findAnagrams(char * s, char * p, int* returnSize){ 8 int mark[MARK_SIZE] = { 0 }; 9 int *result = NULL; 10 int slen = strlen(s); 11 int plen = strlen(p); 12 int i; 13 int l; 14 int r; 15 int len; 16 int count = 0; 17 *returnSize = 0; 18 printf("slen=%d, plen=%d\n",slen,plen); 19 for (i = 0; i < MARK_SIZE; i++) 20 mark[i] = 0; 21 result = (int*)malloc(sizeof(int)*(MAX_STRING_SIZE)); 22 for (i = 0; i < plen; i++) { 23 mark[p[i]]++; 24 printf("mark[%c] = %d\n", p[i],mark[p[i]]); 25 } 26 for(l = 0, r = 0, len = 0; r < slen; r++) { 27 mark[s[r]]--; 28 if(mark[s[r]]>=0) 29 len++; 30 while(r - l + 1 > plen) { 31 mark[s[l]]++; 32 if (mark[s[l]] > 0) { 33 len--; 34 } 35 l++; 36 } 37 if(len == plen) 38 { 39 result[*returnSize] = l; 40 (*returnSize)++; 41 printf("returnSize=%d, l=%d r=%d\n",*returnSize,l,r); 42 } 43 } 44 return result; 45 }