76. Minimum Window Substring && 438. Find All Anagrams in a String
2016-11-20 20:50
405 查看
这个题和Longest
Substring Without Repeating Characters及Substring
with Concatenation of All Words类似。
在Discuss里面有个帖子都总结出这类问题的一个template了,但是写的比较难懂,下面的回复有一个解释的比较清楚,博主也是直接把他的code用Java重新写了一遍。
本来想在初始化map的时候直接把1到2^16这所有的char先放进map,超时,可能创建map耗时过长,只能需要用到什么就创建并put进map
对于需要的字符,因为初始化的时候已经设定好了需要的数量,所以当需要他们的数量全部变为0的时候就是一个可以覆盖的window(但可能包含冗余),在缩小window大小的时候,如果把需要的字符串缩掉了,说明就已经达到了最大能缩小的限度,
而对于不需要的字符,在滑动窗口的时候记录的就是他们在窗口中多出来的量(表示为负值),在取出冗余的过程中,他们永远不会出现需求大于0的情况,因为你最多最多把窗口缩小为0,这个时候那些不用的字符自是变为0而已,所以不需要的字符在Map中一直都是负的或者0
所以一个trick就是在初始化的时候设置需要的字符数量,窗口中无关的字符也把他们放在Map里面
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S =
T =
Minimum window is
Note:
If there is no such window in S that covers all characters in T, return the empty string
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
模板:
For most substring problem, we are given a string and need to find a substring of it which satisfy some restrictions. A general way
is to use a hashmap assisted with two pointers. The template is given below.
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:
Example 2:
思路:有了上面的模板,套进去就OK了
不过这里有更严格的限制,可以写得更加简洁
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list = new ArrayList<>();
if (s == null || s.length() == 0 || p == null || p.length() == 0) return list;
int[] hash = new int[256]; //character hash
//record each character in p to hash
for (char c : p.toCharArray()) {
hash[c]++;
}
//two points, initialize count to p's length
int left = 0, right = 0, count = p.length();
while (right < s.length()) {
//move right everytime, if the character exists in p's hash, decrease the count
//current hash value >= 1 means the character is existing in p
if (hash[s.charAt(right++)]-- >= 1) count--;
//when the count is down to 0, means we found the right anagram
//then add window's left to result list
if (count == 0) list.add(left);
//if we find the window's size equals to p, then we have to move left (narrow the window) to find the new match window
//++ to reset the hash because we kicked out the left
//only increase the count if the character is in p
//the count >= 0 indicate it was original in the hash, cuz it won't go below 0
if (right - left == p.length() && hash[s.charAt(left++)]++ >= 0) count++;
}
return list;
}
Substring Without Repeating Characters及Substring
with Concatenation of All Words类似。
在Discuss里面有个帖子都总结出这类问题的一个template了,但是写的比较难懂,下面的回复有一个解释的比较清楚,博主也是直接把他的code用Java重新写了一遍。
本来想在初始化map的时候直接把1到2^16这所有的char先放进map,超时,可能创建map耗时过长,只能需要用到什么就创建并put进map
对于需要的字符,因为初始化的时候已经设定好了需要的数量,所以当需要他们的数量全部变为0的时候就是一个可以覆盖的window(但可能包含冗余),在缩小window大小的时候,如果把需要的字符串缩掉了,说明就已经达到了最大能缩小的限度,
而对于不需要的字符,在滑动窗口的时候记录的就是他们在窗口中多出来的量(表示为负值),在取出冗余的过程中,他们永远不会出现需求大于0的情况,因为你最多最多把窗口缩小为0,这个时候那些不用的字符自是变为0而已,所以不需要的字符在Map中一直都是负的或者0
所以一个trick就是在初始化的时候设置需要的字符数量,窗口中无关的字符也把他们放在Map里面
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S =
"ADOBECODEBANC"
T =
"ABC"
Minimum window is
"BANC".
Note:
If there is no such window in S that covers all characters in T, return the empty string
"".
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
import java.util.HashMap; import java.util.Map; public class Solution { public String minWindow(S d201 tring s, String t) { // 初始化map Map<Character, Integer> map = new HashMap<Character, Integer>(); // for(int i=0; i<=Character.MAX_CODE_POINT; i++) { // map.put((char)i, 0); // } char[] ss = s.toCharArray(); char[] ts = t.toCharArray(); for(char c : ts) map.put(c, map.containsKey(c) ? map.get(c)+1 : 1); // counter是待match的字符数量 int start = 0, end = 0, counter = t.length(), minStart = 0, minLen = Integer.MAX_VALUE; // 移动end直到找到一个正确的window while(end < s.length()) { // 如果当前的window还需要ss[end]这个字符 if(map.containsKey(ss[end]) && map.get(ss[end]) > 0) counter --; // 因为添加到了window,所以对当前添加的字符减1,不管需不需要这个字符 // 因为后面缩小window可能会用到这个字符 map.put(ss[end], map.containsKey(ss[end]) ? map.get(ss[end]) - 1 : -1); // end任务完成,可以加1 // 当当前window满足时,end++仍然会执行 end ++; // 如果找到了合适的window,就开始移动start来找到更小的window while(counter == 0) { if(end - start < minLen) { minLen = end - start; minStart = start; } // 将要移除start位置上的字符 map.put(ss[start], map.containsKey(ss[start]) ? map.get(ss[start])+1 : 1); // 如果window中间没有跟ss[start]相等的字符补充,那么这个window就不行,跳出循环继续end++找 if(map.containsKey(ss[start]) && map.get(ss[start]) > 0) counter ++; start ++; } } if(minLen != Integer.MAX_VALUE) return s.substring(minStart, minStart + minLen); return ""; } }
模板:
For most substring problem, we are given a string and need to find a substring of it which satisfy some restrictions. A general way
is to use a hashmap assisted with two pointers. The template is given below.
int findSubstring(string s){ vector<int> map(128,0); int counter; // check whether the substring is valid int begin=0, end=0; //two pointers, one point to tail and one head int d; //the length of substring for() { /* initialize the hash map here */ } while(end<s.size()){ if(map[s[end++]]-- ?){ /* modify counter here */ } while(/* counter condition */){ /* update d here if finding minimum*/ //increase begin to make it invalid/valid again if(map[s[begin++]]++ ?){ /*modify counter here*/ } } /* update d here if finding maximum*/ } return d; }
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".
思路:有了上面的模板,套进去就OK了
/* * 想到了满足一定条件的substring问题有个模板,HashMap + start end two pointers * https://discuss.leetcode.com/topic/30941/here-is-a-10-line-template-that-can-solve-most-substring-problems */ public class Solution { public List<Integer> findAnagrams(String s, String p) { List<Integer> rst = new ArrayList<Integer>(); char[] cs = s.toCharArray(); // initialize map Map<Character, Integer> map = new HashMap<Character, Integer>(); for(char c : p.toCharArray()) map.put(c, map.containsKey(c)?map.get(c)+1:1); // two pointers int start = 0, end = 0, count = p.length(); while(end < s.length()) { // modify counter to find a valid but large window if(map.containsKey(cs[end]) && map.get(cs[end]) > 0) count--; map.put(cs[end], map.containsKey(cs[end])?map.get(cs[end])-1:-1); end++; // if found a valid but large window, try to minimize its length while(count == 0) { // specific restrictions if(end - start == p.length()) rst.add(start); // remove start and check valid and update count map.put(cs[start], map.get(cs[start])+1); if(map.get(cs[start]) > 0) count ++; start++; } } return rst; } }
不过这里有更严格的限制,可以写得更加简洁
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list = new ArrayList<>();
if (s == null || s.length() == 0 || p == null || p.length() == 0) return list;
int[] hash = new int[256]; //character hash
//record each character in p to hash
for (char c : p.toCharArray()) {
hash[c]++;
}
//two points, initialize count to p's length
int left = 0, right = 0, count = p.length();
while (right < s.length()) {
//move right everytime, if the character exists in p's hash, decrease the count
//current hash value >= 1 means the character is existing in p
if (hash[s.charAt(right++)]-- >= 1) count--;
//when the count is down to 0, means we found the right anagram
//then add window's left to result list
if (count == 0) list.add(left);
//if we find the window's size equals to p, then we have to move left (narrow the window) to find the new match window
//++ to reset the hash because we kicked out the left
//only increase the count if the character is in p
//the count >= 0 indicate it was original in the hash, cuz it won't go below 0
if (right - left == p.length() && hash[s.charAt(left++)]++ >= 0) count++;
}
return list;
}
相关文章推荐
- leetcode[76] Minimum Window Substring
- LeetCode(76)Minimum Window Substring
- LeetCode(76) Minimum Window Substring
- 76. Minimum Window Substring My Submissions Question
- 76. Minimum Window Substring
- LeetCode 76 Minimum Window Substring
- leetcode 76 Minimum Window Substring
- **Minimum Window Substring & String类问题模板
- LeetCode76——Minimum Window Substring
- 76 - Minimum Window Substring
- [leetcode] 76 Minimum Window Substring
- [leetcode-76]Minimum Window Substring(java)
- 76. Minimum Window Substring
- 76. Minimum Window Substring
- Interleaving String & Candy & Minimum Window Substring
- leetcode[76]Minimum Window Substring
- [leedcode 76] Minimum Window Substring
- leetcode 76: Minimum Window Substring
- Leetcode-76 Minimum Window Substring
- leetcode@ [30/76] Substring with Concatenation of All Words & Minimum Window Substring (Hashtable, Two Pointers)