solution: Sliding window + counter, O(N), O(K)
simplest approach: sliding window + two counter hashmaps letter -> its count. The first hashmap is a reference counter pCount for string p, and the second one is a counter sCount for a string in the sliding window.
The idea is to move the sliding window along the string s, recompute the second hashmap sCount in a constant time, and compare it with the first hashmap pCount. If sCount == pCount, then the string in the sliding window is a permutation of string p, and one could add its start position in the output list.
class Solution {
public List<Integer> findAnagrams(String s, String p) {
// count char frequency in p
Map<Character, Integer> pmap = new HashMap<>();
for (int i = 0; i < p.length(); i++) {
char c = p.charAt(i);
pmap.put(c, pmap.getOrDefault(c, 0) + 1);
}
int i = 0, j = 0;
List<Integer> res = new ArrayList<>();
Map<Character, Integer> smap = new HashMap<>();
while (i < s.length() && j < s.length()) {
// always to update smap for every character in s (rather than only those in p)
char r = s.charAt(j);
smap.put(r, smap.getOrDefault(r, 0) + 1);
// contract window size via i++ when window exceed p's size
if (j - i >= p.length()) {
char l = s.charAt(i);
smap.put(l, smap.get(l) - 1);
if (smap.get(l) == 0) {
smap.remove(l);
}
i++;
}
if (smap.equals(pmap)) {
res.add(i);
}
j++; // expand window size
}
return res;
}
}
class Solution { public List<Integer> findAnagrams(String s, String p) { int[] pFreq = new int[26]; for (int i = 0; i < p.length(); i++) { char c = p.charAt(i); pFreq[c - 'a']++; } int i = 0, j = 0; List<Integer> res = new ArrayList<>(); int[] sFreq = new int[26]; while (i < s.length() && j < s.length()) { // always to update smap for every character in s (rather than only those in p) char r = s.charAt(j); sFreq[r - 'a']++; if (j - i >= p.length()) { char l = s.charAt(i); sFreq[l - 'a']--; i++; } if (Arrays.equals(sFreq, pFreq)) { // Arrays.equals, not a.equals(b) res.add(i); } j++; } return res; } }