給定一個字符串 s 和一個非空字符串 p,找到 s 中所有是 p 的字母異位詞的子串,返回這些子串的起始索引。
字符串只包含小寫英文字母,并且字符串 s 和 p 的長度都不超過 20100。
說明:
字母異位詞指字母相同,但排列不同的字符串。
不考慮答案輸出的順序。
示例 1:
輸入:
s: "cbaebabacd" p: "abc"
輸出:
[0, 6]
解釋:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母異位詞。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母異位詞。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string
著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有。商業(yè)轉(zhuǎn)載請聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
public List<Integer> findAnagrams(String s, String p) {
char[] arrS = s.toCharArray();
char[] arrP = p.toCharArray();
// 接收最后返回的結(jié)果
List<Integer> ans = new ArrayList<Integer>();
// 定義一個 needs 數(shù)組來看 arrP 中包含元素的個數(shù)
int[] needs = new int[26];
// 定義一個 window 數(shù)組來看滑動窗口中是否有 arrP 中的元素,并記錄出現(xiàn)的個數(shù)
int[] window = new int[26];
// 先將 arrP 中的元素保存到 needs 數(shù)組中
for (int i = 0; i < arrP.length; i++) {
needs[arrP[i] - 'a'] += 1;
}
// 定義滑動窗口的兩端
int left = 0;
int right = 0;
// 右窗口開始不斷向右移動
while (right < arrS.length) {
int curR = arrS[right] - 'a';
right++;
// 將右窗口當(dāng)前訪問到的元素 curR 個數(shù)加 1
window[curR] += 1;
// 當(dāng) window 數(shù)組中 curR 比 needs 數(shù)組中對應(yīng)元素的個數(shù)要多的時候就該移動左窗口指針
// cbaebabacd abc 為例,當(dāng)right移動到e的時候 會一直循環(huán) 讓left 走到e 才罷休 然后從e開始計算
while (window[curR] > needs[curR]) {
int curL = arrS[left] - 'a';
left++;
// 將左窗口當(dāng)前訪問到的元素 curL 個數(shù)減 1
window[curL] -= 1;
}
// 這里將所有符合要求的左窗口索引放入到了接收結(jié)果的 List 中
if (right - left == arrP.length) {
ans.add(left);
}
}
return ans;
}
第二種解法利用 total
public List<Integer> findAnagrams(String s, String p) {
if(s == null || s.length() == 0) return new ArrayList<>();
List<Integer> res = new ArrayList<>();
int[] needs = new int[26]; //由于都是小寫字母,因此直接用26個長度的數(shù)組代替原來的HashMap
int[] window = new int[26];
int left = 0, right = 0, total = p.length(); //用total檢測窗口中是否已經(jīng)涵蓋了p中的字符
for(char ch : p.toCharArray()){
needs[ch - 'a'] ++;
}
while(right < s.length()){
char chr = s.charAt(right);
if(needs[chr - 'a'] > 0){
window[chr - 'a'] ++;
if(window[chr - 'a'] <= needs[chr - 'a']){
total --;
}
}
while(total == 0){
if(right-left+1 == p.length()){
res.add(left);
}
char chl = s.charAt(left);
if(needs[chl - 'a'] > 0){
window[chl - 'a'] --;
if(window[chl - 'a'] < needs[chl - 'a']){
total ++;
}
}
left ++;
}
right ++;
}
return res;
}
解法相同的 還有
242. 有效的字母異位詞
public boolean isAnagram(String s, String t) {
char[] sourceArr = s.toCharArray();
char[] targetArr = t.toCharArray();
if (sourceArr.length != targetArr.length) {
return false;
}
int[] sourceFreq = new int[256];
int[] targetFreq = new int[256];
for (int i = 0; i < targetArr.length; i++) {
targetFreq[targetArr[i]]++;
}
int total = sourceArr.length;
int left = 0;
int right = 0;
while (right < sourceArr.length) {
char currentCharIndex = sourceArr[right];
if (targetFreq[currentCharIndex] <= 0) {
return false;
}
sourceFreq[currentCharIndex]++;
if (sourceFreq[currentCharIndex] <= targetFreq[currentCharIndex]) {
total--;
} else {
return false;
}
while (total == 0) {
char leftCharIndex = sourceArr[left];
if (targetFreq[leftCharIndex] <= 0) {
return false;
}
sourceFreq[leftCharIndex]--;
if (sourceFreq[leftCharIndex] <= targetFreq[leftCharIndex]) {
total++;
}
left++;
}
right++;
}
return true;
}