438. Find All Anagrams in a String
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".
public class Solution { public List<Integer> findAnagrams(String s, String t) { List<Integer> result = new LinkedList<>(); if(t.length()> s.length()) return result; Map<Character, Integer> map = new HashMap<>(); for(char c : t.toCharArray()){ map.put(c, map.getOrDefault(c, 0) + 1); } int counter = map.size(); int begin = 0, end = 0; int head = 0; int len = Integer.MAX_VALUE; while(end < s.length()){ char c = s.charAt(end); if( map.containsKey(c) ){ map.put(c, map.get(c)-1); if(map.get(c) == 0) counter--; System.out.print(counter + " "); System.out.println(c + " " + map.get(c)); } end++; while(counter == 0){ char tempc = s.charAt(begin); if(map.containsKey(tempc)){ map.put(tempc, map.get(tempc) + 1); if(map.get(tempc) > 0){ counter++; } } if(end-begin == t.length()){ result.add(begin); } System.out.println("begin " + begin); begin++; } } return result; } }
这种方法固然好,但有点繁琐啊
class Solution { public List<Integer> findAnagrams(String s, String p) { int[] hash = new int[26]; int sle = s.length(), ple = p.length(); for(char c : p.toCharArray()) hash[c - 'a']++; char[] sarr = s.toCharArray(); List<Integer> res = new ArrayList(); int count = 0, l = 0; for(int r = 0; r < sle; r++) { hash[sarr[r] - 'a']--; if(hash[sarr[r] - 'a'] >= 0) count++; if(r - l + 1 > ple) { hash[sarr[l] - 'a']++; if(hash[sarr[l] - 'a'] > 0) count--; l++; } if(count == ple) res.add(l); } return res; } }
首先它是一个固定长度的window,然后套用模板,先给每个p string里的char hash一下,然后用count来表示当前有效长度,当有效长度==p。length(),说明找到了一个有效substring,即从l到r。
从左向右遍历,先hash--,如果hash仍然≥0,说明当前是一个有效的char,count++。
然后是判断window缩小条件,r-l + 1》ple,说明window过长,需要减小一位。
现在要把左边l的hash还回去,还要判断还回去的是不是有效的char,如果是的话,count--。记得l++来保证window size正常。
最后就是判断count == ple时,就是一个正确答案。
https://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=544207&page=1
参考这位大佬的模板,更加简洁
模板分为
public int slidingWindowTemplate(String[] a, ...) { // 输入参数有效性判断 if (...) { ... } // 申请一个散列,用于记录窗口中具体元素的个数情况 // 这里用数组的形式呈现,也可以考虑其他数据结构 int[] hash = new int[...]; // 预处理(可省), 一般情况是改变 hash ... // l 表示左指针 // count 记录当前的条件,具体根据题目要求来定义 // result 用来存放结果 int l = 0, count = ..., result = ...; for (int r = 0; r < A.length; ++r) { // 更新新元素在散列中的数量 hash[A[r]]--; // 根据窗口的变更结果来改变条件值 if (hash[A[r]] == ...) { count++; } // 如果当前条件不满足,移动左指针直至条件满足为止 while (count > K || ...) { ... if (...) { count--; } hash[A[l]]++; l++; } // 更新结果 results = ... } return results; }
很好很强大