Sliding window algorithm detailed explanation notes
Introduction
What is a sliding window?
In fact, it is a queue, such as abcabcbb in the example. Entering this queue (window) meets the requirements for abc. When entering a, the queue becomes abca, which does not meet the requirements. So, we're going to move this queue!
How to move?
We just need to move out the elements on the left of the queue until the requirements of the topic are met!
Always maintain such a queue, find out the longest length of the queue and find the solution!
Time complexity: O(n)
What scenarios use sliding windows?
A: if we find an interval that meets the requirements, and it is meaningless for the right boundary of the interval to expand to the right, we can move the left boundary to the position that does not meet the requirements. Then move the right boundary and continue until the right boundary of the interval reaches the end point of the whole.
Sliding window general template:
Pseudo code template: Here is a definition res Update the result variable,The following code will this res Variable optimization is eliminated def findSubArray(nums): N = len(nums) # Array / string length left, right = 0, 0 # Double pointer, indicating the currently traversed interval [left, right], closed interval sums = 0 # It is used to count whether the subarray / subinterval is valid. It may be changed to sum / count according to the topic res = 0 # Save the maximum subarray / substring length that meets the requirements of the topic while right < N: # When the pointer on the right does not search for the end of the array / string sums += nums[right] # Increase the sum / count of numbers / characters of the current right pointer while section[left, right]Not in accordance with the meaning of the question:# At this time, you need to move the left pointer until you find an interval that meets the meaning of the question sums -= nums[left] # Before moving the left pointer, you need to reduce the sum / count of characters in the left position from the counter left += 1 # Really move the left pointer, and be careful not to write inversely with the above line of code # At the end of while, we find a subarray / substring that meets the requirements of the topic res = max(res, right - left + 1) # Results need to be updated right += 1 # Move the right pointer to explore a new interval return res convert to java code: public int findwindow(arr) { //Note that the nums array here may be the arr array in its own condition, or it may need to be converted # arr --> nums int n = nums.length(); //Gets the length of a specific array int left,right = 0; //Double pointer, indicating the currently traversed interval [left, right], closed interval int sum/cnt = 0; // It is used to count whether the subarray / subinterval is valid. It may be changed to sum / count according to the topic while(right < n) { sum/cnt += nums[right]; if(section[left, right]Not in accordance with the meaning of the question) { //At this time, the left pointer needs to be moved, and the sum / count of characters at the left position needs to be reduced from sum/cnt sum/cnt -= nums[left]; left++;Move the left pointer, and be careful not to write backwards with the above line of code } right++;Move the right pointer to explore a new interval } //Finally, the result set is returned: because the right pointer above is + + one more time, right - left is returned here return right - left; } //Convert to javaScript code: var equalSubstring = function(arr) { //Note that the nums array here may be the arr array in its own condition, or it may need to be converted # arr --> nums let n = nums.length(); //Gets the length of a specific array let left,right = 0; //Double pointer, indicating the currently traversed interval [left, right], closed interval let sum/cnt = 0; // It is used to count whether the subarray / subinterval is valid. It may be changed to sum / count according to the topic while(right < n) { sum/cnt += nums[right]; if(section[left, right]Not in accordance with the meaning of the question) { //At this time, the left pointer needs to be moved, and the sum / count of characters at the left position needs to be reduced from sum/cnt sum/cnt -= nums[left]; left++;Move the left pointer, and be careful not to write backwards with the above line of code } right++;Move the right pointer to explore a new interval } //Finally, the result set is returned: because the right pointer above is + + one more time, right - left is returned here return right - left; };
Part I: problem analysis
Title:
1. The longest substring without repeated characters: corresponding to question 3 of LeetCode
Given a string, please find the length of the longest substring that does not contain duplicate characters.
Example 1:
input: s = "abcabcbb" output: 3 explain: Because the longest substring without duplicate characters is "abc",So its length is 3.
Example 2:
input: s = "bbbbb" output: 1 explain: Because the longest substring without duplicate characters is "b",So its length is 1.
Example 3:
input: s = "pwwkew" output: 3 explain: Because the longest substring without duplicate characters is "wke",So its length is 3. Please note that your answer must be the length of the substring,"pwke" Is a subsequence, not a substring.
Example 4:
input: s = "" output: 0
Tips:
- 0 <= s.length <= 5 * 104
- s consists of English letters, numbers, symbols and spaces
2 concatenate substrings of all words: corresponding to question 30 of LeetCode
Given a string s and some words of the same length * * words** Find the starting position of the substring in s that can be formed by concatenation of all words in words.
Note that the substring should completely match the words in words, and there should be no other characters in the middle, but the order of concatenation of words does not need to be considered.
Example 1:
Input: s = "barfoothefoobarman", words = ["foo","bar"] Output:[0,9] Explanation: The substrings starting from indexes 0 and 9 are "barfoo" and "foobar" . The order of output is not important, [9,0] It is also a valid answer.
Example 2:
Input: s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"] Output:[]
3 minimum coverage substring: corresponding to question 76 of LeetCode
Give you a string s and a string t. Returns the smallest substring of s covering t all characters. If there is no substring covering t all characters in s, the empty string "" is returned.
**Note: * * if there is such a substring in s, we guarantee that it is the only answer.
Example 1:
Input: s = "ADOBECODEBANC", t = "ABC" Output:"BANC"
Example 2:
Input: s = "a", t = "a" Output:"a"
Tips:
- 1 <= s.length, t.length <= 105
- s and t consist of English letters
Advanced: can you design an algorithm to solve this problem in o(n) time?
4 given a string s, find the longest substring t containing at most two different characters: corresponding to question 159 of LeetCode
Example 1:
input: "eceba" output: 3 explain: t yes "ece",The length is 3.
Example 2:
input: "ccaabbb" output: 5 explain: t yes "aabbb",The length is 5.
5 given a string s, find the longest substring t containing at most k different characters: corresponding to question 340 of LeetCode
Example 1:
input: s = "eceba", k = 2 output: 3 explain: be t by "ece",So the length is 3.
Example 2:
input: s = "aa", k = 1 output: 2 explain: be t by "aa",So the length is 2.
6 the longest mountain range in the array: corresponding to question 845 of LeetCode
Any continuous subarray B in array A that meets the following attributes is called "mountain range":
- B.length >= 3
- There is 0 < I < b.length - 1 such that B [0] < B [1] <... B [I-1] < B [i] > b [i + 1] >... > b [b.length - 1]
(Note: B can be any subarray of A, including the entire array A.)
Give an integer array A and return the length of the longest "mountain".
Returns 0 if it does not contain mountains.
Example 1:
Input:[2,1,4,7,3,2,5] Output: 5 Explanation: the longest "mountain range" is [1,4,7,3,2],The length is 5.
Example 2:
Input:[2,2,2] Output: 0 Explanation: excluding "mountains".
Tips:
- 0 <= A.length <= 10000
- 0 <= A[i] <= 10000
Resolution:
Question 1: the longest substring without repeated characters. This is the third question of LeetCode. You must have finished it
Problem analysis:
Graphic analysis:
Code implementation:
public int lengthOfLongestSubstring(String s) { //Defines the length of the s string as n int n = s.length(); //If n < = 1, max is the length of the string itself and returns n directly if(n <= 1) { return n; } //We define maxLength as the length of the largest non repeating substring int maxLength = 0; //Define a HashMap: where key is the character in s and value is the constantly updated index HashMap<Character,Integer> map = new HashMap<>(); //Defines the left pointer variable of the sliding window, with an initial value of 0 int left = 0; for(int i = 0; i < n;i++) { if(map.containsKey(s.charAt(i))) { //If the current key value [character exists in the map] //We need to update the left pointer: take the maximum value of the previous left pointer and the pointer of the character that appears before and shift it one bit to the right left = Math.max(left,map.get(s.charAt(i) + 1)); } //If it does not exist, the key value is added to the map collection map.put(s.charAt(i),i); maxLength = Math.max(maxLength,i - left + 1); } //Finally, the maximum value maxLength is returned to solve the problem return maxLength; }
Question 2: use HashMap method + sliding window method to solve [PS: I don't understand it. Tell me after reading...]
Here we focus on the sliding window method:
1 because the length of a word [we define it as one_word] is fixed, a word can be regarded as a unit
2 use sliding window for words, and the step size between units is one_word
3 at 0 - one_ Within the scope of word, each serves as the starting point of the sliding window to slide word_num times, you can overwrite various combinations of all strings
Illustration:
We take s = "barfootefoobarman", words = ["foo", "bar"] as an example for graphical analysis
Code implementation:
//The sliding window algorithm is used to solve the problem public List<Integer> findSubstring(String s, String[] words) { //We define the returned result set res List<Integer> res = new ArrayList<>(); if (s == null || s.length() == 0 || words == null || words.length == 0) return res; //Define a Map collection: used to store each word in words and the number of occurrences of the word HashMap<String,Integer> map = new HashMap<>(); //Since the length of each word in words is fixed, we define one_word is the length of the word element in the words array int one_word = words[0].length(); //Gets the length of the words array int word_num = words.length; //Define all_len is the total length of words int all_len = one_word * word_num; for (String word : words) { map.put(word,map.getOrDefault(word,0) + 1); } //Traverse [0,one_word] for (int i = 0; i < one_word; i++) { //Define two pointers left,right: to represent the index values of the left and right windows int left = i; int right = i; //Define a count counter with an initial value of 0 int count = 0; //Define tmap: used to count word words that meet the conditions HashMap<String,Integer> tmap = new HashMap<>(); //When the index of the right window does not exceed the length of the s String while (right + one_word <= s.length()) { //We follow one_ Select a window according to the length of word String window = s.substring(right,right + one_word); //Add it to tmap tmap.put(window,tmap.getOrDefault(window,0) + 1); //At the same time, the index value of the right window is shifted backward_ Word units right = right + one_word; //Increase the count counter by 1 count++; //If the number of windows in this window is greater than the number of windows in the map set, such as "bar","foo", but it is "barfoobar" at this time while (tmap.getOrDefault(window,0) > map.getOrDefault(window,0)) { //We need to move the left window to the right: get one_word length window String window2 = s.substring(left,left + one_word); //And reduce the number of count counters by 1 count--; //At the same time, reduce the number of windows in tmp by 1 tmap.put(window2,tmap.getOrDefault(window2,0) - 1); //Move the left pointer to the right again_ Word units left = left + one_word; } //If the number of count s = = word_num, that is, the length of the words array, indicates that the left index position is a result set, which is directly added to res if (count == word_num) res.add(left); } } return res; } //Another way to achieve //Solve using map public List<Integer> findSubstring02(String s, String[] words) { //Define result set List<Integer> res = new ArrayList<>(); int n = words.length; if (n == 0) return res; int len = words[0].length(); //Get the length of each word (equal length) //map: stores the words of the words array and the number of occurrences Map<String,Integer> map = new HashMap<>(); for (int i = 0; i < n; i++) { map.put(words[i],map.getOrDefault(words[i],0) + 1); } //Record the total length of words in words int words_len = len * n; for (int i = 0; i < s.length() - words_len + 1; i++) { //Define a map: record the words contained in the currently scanned string and the number of times they appear Map<String,Integer> hasWords = new HashMap<>(); int number = 0; //Record the number of occurrences of the word while (number < n) { //Get current String word = s.substring(i + number * len,i + (number + 1) * len); //Judge whether the key of the word exists in the map if (map.containsKey(word)) { hasWords.put(word,hasWords.getOrDefault(word,0) + 1); //Compare the number of occurrences of the current word in the two maps at this time. If the value of the key in hasWords is greater than the value in the map, it indicates that it does not match and exit directly if (hasWords.get(word) > map.get(word)) { break; } }else { //key that does not contain the word break; } number++; } //Exit and judge whether the number of number is equal to n if (number == n) { res.add(i); } } return res; }
Question 3: minimum covering substring problem
Train of thought analysis:
Create a new arcr [128] to count the number of occurrences of each character in t,
Create a new window[128] to count the number of occurrences of each character in the sliding window.
First, count the number of times each letter appears in T
Create two new variables, left and right, to represent the left and right of the sliding window respectively.
Create a new variable count to indicate how many characters have been found in the current window.
Take S = "Adobe codebanc", T = "ABC" as an example, and then slide the window according to the law shown in the figure.
Code implementation:
//The sliding window method is used to solve public String minWindow(String s, String t) { //Obtain the length of s and the length of t respectively int n = s.length(); int m = t.length(); //If s and T are null or empty strings, or the length of s string is less than the length of t string, it will directly return "" if (n < m || s == null || s == "" || t == "" || t == null) return ""; //Record the number of occurrences of each character in the t string, because the total number of characters in ASCII code is 128, and the maximum length of the index array is 128 int[] cArr = new int[128]; //Redefine window array: record the number of times each character appears in the sliding window int[] window = new int[128]; for (int i = 0; i < m; i++) { //char type will be automatically converted into int type character in java. The int value range is 0 ~ 127 cArr[t.charAt(i)]++; } //Define two pointer variables, left and right, with initialization values of 0 int left = 0; int right = 0; String res = ""; //Defines a counter that records the number of characters in the current window that contain the t string int count = 0; //Define minWindow: record the length of characters required by the shortest window that meets the requirements int minWindow = s.length() + 1; while (right < s.length()) { //Gets the value corresponding to the right index in the current s string char ch = s.charAt(right); //Increase the number of this character in the sliding window by 1 window[ch]++; if (cArr[ch] > 0 && cArr[ch] >= window[ch]) { count++; } //Move the pointer to the position where the condition is not met while (count == m) { ch = s.charAt(left); //If the ch character is one of the t strings, it will count -- and exit at the next cycle if (cArr[ch] > 0 && cArr[ch] == window[ch]) { count--; } //If the length of right - left + 1 is less than the length of minWindow if (right - left + 1 < minWindow) { //Update the length of minWindow and the result set res minWindow = right - left + 1; res = s.substring(left,right + 1); } //After selecting ch, we will reduce the number of CH characters in the window by 1 window[ch]--; //At the same time, move the left pointer one bit to the right left++; } //If count= t. Length (m), move the right pointer to the right and continue to judge right++; } return res; }
Question 4: given a string s, find the longest substring t containing at most 2 different characters
Train of thought analysis:
Take "ccaabbb" as an example, as shown below
Code implementation:
public class FindLengthOfLongestSubstringTwoDistinct { public static void main(String[] args) { String s = "ccaabbb"; FindLengthOfLongestSubstringTwoDistinct solution = new FindLengthOfLongestSubstringTwoDistinct(); int length = solution.lengthOfLongestSubstringTwoDistinct(s); System.out.println("The longest substring containing at most two different characters t Length of : " + length); } //Use sliding window + HashMap to solve this problem public int lengthOfLongestSubstringTwoDistinct(String s) { //Gets the length of the s string, n int n = s.length(); if (n <= 2) {//If n is less than or equal to 2, n is returned directly return n; } int length = 2;//The length of the longest substring t containing at most two different characters is 2 //K is the corresponding character and V is the position of the last occurrence HashMap<Character,Integer> map = new HashMap<>(); //Defines the left and right pointers, which initially point to the s string 0 index int left = 0; int right = 0; //In general, the loop condition of the while pointer is the right pointer while (right < n) { //If the number of different key s in the current map set is less than 3, you can continue to expand to the right if (map.size() < 3) { map.put(s.charAt(right),right++); } //If there are different key s in the map at this time, that is, the number of different characters is equal to 3 if (map.size() == 3) { //We get the lowest index position of the existing characters in the current map set at this time int index = Collections.min(map.values()); //We remove the value of the lowest index at this time map.remove(s.charAt(index)); //And update the left pointer to the position of the value index + 1 left = index + 1; } //Update length (the length of the longest substring t) length = Math.max(length,right - left); } //Finally, the value of length is returned return length; } }
Question 5: given a string s, find the longest substring t containing at most k different characters
Train of thought solution: is it handy
Question 6: the longest mountain range in the array
Train of thought analysis:
//The sliding window method is solved public int longestMountain(int[] A) { int len = A.length; //If the length of array A is 3: smaller, 0 is returned directly if (A.length < 3) return 0; int longest = 0; for (int i = 0; i < len - 2; i++) { //Find the initial small mountain range, that is, there is a [i] < a [i + 1] < a [i + 2] if (A[i] < A[i+1] && A[i+1] > A[i+2]) { //Extend the mountain range to the left from the index position of i - 1 and update the maximum length of the mountain range int j = i - 1; //The definition initialization length is 3 int window = 3; //Define the left pointer, pointing to A[i] int left = A[i]; while (j >= 0 && A[j] < left) {//Extend the window to the left left = A[j]; j = j - 1; window = window + 1; } //Extend the mountain range to the right from the index position of i + 3 and update the maximum length of the mountain range j = i + 3; //Define that the right pointer points to A[i + 2] int right = A[i+2]; while (j < len && A[j] < right) {//Extend the window to the right right = A[j]; j = j + 1; window = window + 1; } //After sliding the window left and right, update the length of the longest mountain this time longest = Math.max(longest,window); } } //Returns the last longest length return longest; } //Compact code version public int longestMountain(int[] arr) { int res = 0; if (arr.length < 3) return res; int n = arr.length; for (int i = 1; i < n - 1; i++) { //Pruning operation if (arr[i - 1] >= arr[i] || arr[i] <= arr[i + 1]) continue; //Taking this point as the top of the mountain, we search the mountain left and right respectively int left = i; while (left > 0 && arr[left] > arr[left - 1]) { --left; } int right = i; while (right < n - 1 && arr[right] > arr[right + 1]) { ++right; } //Update the length of the longest mountain range at this time res = Math.max(res,right - left + 1); } return res; }
Part II: actual combat
Question1: 424. Longest repeated character after replacement
Give you a string composed of only uppercase English letters. You can replace characters at any position with other characters, up to k times in total. After performing the above operations, find the length of the longest substring containing repeated letters.
**Note: * * string length and k will not exceed 104.
Example 1:
Input: s = "ABAB", k = 2 Output: 4 Explanation: use two'A'Replace with two'B',vice versa.
Example 2:
Input: s = "AABABBA", k = 1 Output: 4 Explanation: Put the middle one'A'Replace with'B',String becomes "AABBBBA". Substring "BBBB" There is the longest repeating letter, The answer is 4.
Resolution:
Code implementation:
public int characterReplacement(String s, int k) { //Gets the length of the s string int n = s.length; //Define the two pointer variables left and right of the window, and point to the position where the index of the s string is 0 int left = 0,right = 0; //Defines the maximum number of occurrences of repeated characters in the result set window and the current window int window = 0,int cnt = 0; //Define an array counts[26]: record the number of occurrences of each character //while loop: loop condition right < n while(right < n) { //Add 1 to the number of occurrences of the right index character at this time counts[s.charAt(right) - 'a']++; //Traverse the counts array and update the value of cnt for(int i = 0; i < 26; i++) { cnt = Math.max(cnt,counts[i]); } //Judge the size of the window at this time - whether the number cnt of the longest repeated characters is greater than the length K of the replaceable characters? //If greater than, the window is zoomed back from left if(right - left + 1 - cnt > k) { counts[s.charAt(i) - 'a']--; left++; }else { //Otherwise, we update the size of the window that meets the requirements at this time window = Math.max(window,right - left + 1); } //Move the right pointer to the right right++; } //Return result set return window; } //Another way of writing public int characterReplacement(String s, int k) { int n = s.length(); //Gets the length of the s string int left = 0,right = 0; int[] counts = new int[26]; //Record the number of occurrences of each character in the current window int cnt = 0; //Record the maximum number of characters in the current window int res = 0; //Record the result, that is, the length of the longest substring while (right < n) { counts[s.charAt(right) - 'A']++; //Gets the number of characters that appear most in the window at this time for (int i = 0; i < 26; i++) { cnt = Math.max(cnt,counts[i]); } while (right - left + 1 - cnt > k) { counts[s.charAt(left) - 'A']--; left++; } //The res is updated res = Math.max(res,right - left + 1); } return res; } //Re optimization public int characterReplacement02(String s, int k) { int n = s.length(); //Gets the length of the s string int left = 0,right = 0; int[] counts = new int[26]; //Record the number of occurrences of each character in the current window int cnt = 0; //Record the maximum number of characters in the current window int res = 0; //Record the result, that is, the length of the longest substring while (right < n) { counts[s.charAt(right) - 'A']++; //Gets the number of characters that appear most in the window at this time for (int i = 0; i < 26; i++) { cnt = Math.max(cnt,counts[i]); } if (right - left + 1 - cnt > k) { counts[s.charAt(left) - 'A']--; left++; } right++; } return right - left; }
Question2:480. Sliding window median
The median is the number in the middle of the ordered sequence. If the length of the sequence is even, there is no middle number; At this time, the median is the average of the two numbers in the middle.
For example:
- [2,3,4], the median is 3
- [2,3], the median is (2 + 3) / 2 = 2.5
Give you an array nums, with a window of length k sliding from the leftmost to the rightmost. There are k numbers in the window, and each time the window moves 1 bit to the right. Your task is to find the median of the elements in the new window after each window move, and output the array composed of them.
Example:
Give nums = [1,3,-1,-3,5,3,6,7], and k = 3.
window position median --------------- ----- [1 3 -1] -3 5 3 6 7 1 1 [3 -1 -3] 5 3 6 7 -1 1 3 [-1 -3 5] 3 6 7 -1 1 3 -1 [-3 5 3] 6 7 3 1 3 -1 -3 [5 3 6] 7 5 1 3 -1 -3 5 [3 6 7] 6
Therefore, the median array [1, - 1, - 1,3,5,6] of the sliding window is returned
Tips:
- You can assume that k is always valid, that is, k is always less than or equal to the number of elements of the input non empty array.
- An answer with an error of 10 ^ - 5 from the true value will be regarded as the correct answer.
Resolution:
Use the sliding window to solve:
Because the problem requires us to solve the value of the median of the specified size window [from left to right] in the array, we define a window with a length of k, and complete the movement of the window by removing the elements of the left boundary and adding the elements of the right boundary. Each time we slide, we sort to obtain the median at this time
code:
public double[] medianSlidingWindow(int[] nums, int k) { //Gets the length n of the num array int n = nums.length; //At this point, the length of our result set array is n - k + 1 double[] ans = new double[n - k + 1]; //If k is an odd number at this time, we return the value of the intermediate index //If k is an even number at this time, we return the average of the middle two elements int flag = k % 2 == 0 ? 0 : 1;//A flag of 0 means that there are even windows, and a flag of 1 means that there are odd windows int left = 0,right = k - 1; //Define a window window: use the set List List<Integer> window = new ArrayList<>(); for(int i = left; i < k; i++) { window.add(nums[i]); } //Define a counter index int index = 0; while(right < n) { if(right >= k) { window.add(nums[right]); } //Sort window s Collections.sort(window); if (flag == 0) { //If the window size is even ans[index++] = window.get(k / 2 - 1) / 2.0 + window.get(k / 2) / 2.0; }else { //If the window size is odd ans[index++] = window.get(k / 2); } window.remove(new Integer(nums[left++]));//Remove the value of the left boundary of the window to move one bit to the right right++; } //Exit the while loop and return the result set ans return ans; }
Question3: 567. Arrangement of strings
Given two strings s1 and s2, write a function to determine whether s2 contains the arrangement of s1.
In other words, one of the permutations of the first string is a substring of the second string.
Example 1:
input: s1 = "ab" s2 = "eidbaooo" output: True explain: s2 contain s1 One of the permutations of ("ba").
Example 2:
input: s1= "ab" s2 = "eidboaoo" output: False
Tips:
- The input string contains only lowercase letters
- Both strings are between [1, 10000] in length
Resolution:
We judge whether the string s2 contains the arrangement of s1, which is equivalent to the number of occurrences of each character of s1, just in the number of occurrences of each character of a continuous subsequence of s2:
Then we can define a freq array: record the number of occurrences of each character in the string s1
Then define a num array: update the number of occurrences of each character in the record s2 string
Define cnt counter at the same time: record the number of characters contained in the current window [continuous substring sequence of s2]
Start index left = right = 0,while loop condition: right < n
(1) If the character of the right index of the current s2 does not appear in s1, skip the index directly and clear the previous cnt counter and num array
(2) Otherwise, we will increase the number of characters in the right index by 1 and the number of cnt counters by 1
(3) If the number of right indexes in s2 > the number of right indexes in S1, we choose to recursively remove the value of the left index until the window meets the requirements. At the same time, we choose to move the right index to the right
(4) If the value of the cnt counter at this time is better equal to the length of the s1 string, it means that s2 contains an arrangement of s1 at this time
Code implementation:
public boolean checkInclusion(String s1, String s2) { //Obtain the length m of s1 string and the length n of s2 string respectively int m = s1.length(); int n = s2.length(); if (m > n) return false; int[] freq = new int[26]; for (int i = 0; i < m; i++) { freq[s1.charAt(i) - 'a']++; } int[] nums = new int[26]; int cnt = 0; int left = 0; int right = 0; while (right < n) { if (freq[s2.charAt(right) - 'a'] == 0) { //Indicates that the s1 character does not exist in the string right++; left = right; cnt = 0; Arrays.fill(nums,0); }else { nums[s2.charAt(right) - 'a']++; cnt++; while (nums[s2.charAt(right) - 'a'] > freq[s2.charAt(right) - 'a']) { //Select to recursively remove the value of the left pointer cnt--; nums[s2.charAt(left) - 'a']--; left++; } right++; if (cnt == m) { return true; } } } return false; }
Question4: 995. Minimum number of flips of k consecutive bits
In array A containing only 0 and 1, A K-bit flip includes selecting A (continuous) subarray of length K and changing each 0 in the subarray to 1 and each 1 to 0.
Returns the minimum number of K-bit flips required so that the array has no elements with a value of 0. If this is not possible, return - 1.
Example 1:
Input: A = [0,1,0], K = 1 Output: 2 Explanation: flip first A[0],Then flip A[2].
Example 2:
Input: A = [1,1,0], K = 2 Output:-1 Explanation: no matter how we flip a subarray of size 2, we can't make the array into [1,1,1].
Example 3:
Input: A = [0,0,0,1,0,1,1,0], K = 3 Output: 3 Explanation: Flip A[0],A[1],A[2]: A become [1,1,1,1,0,1,1,0] Flip A[4],A[5],A[6]: A become [1,1,1,1,1,0,0,0] Flip A[5],A[6],A[7]: A become [1,1,1,1,1,1,1,1]
Tips:
- 1 <= A.length <= 30000
- 1 <= K <= A.length
Resolution:
Greedy strategy: if the value of the current index is 0, we will flip it k times back from the current position!
This greedy strategy + exchange method will be very slow due to the real exchange operation. Only js passed
public int minKBitFlips01(int[] A, int K) { //Gets the length of the A array int n = A.length; int right = 0; int cnt = 0; while (right < n) { //If the value of the right index position is 0 at this time, and the number of [right,n] remaining elements is less than K at this time, all 1 can not be flipped, and we directly return - 1 if (A[right] == 0 && n - right < K) { return -1; } //If A[right] == 1: we directly move the right pointer one bit to the right, continue //If A[right] == 0: we choose to flip back the K digits from right if (A[right] == 0) { //Increase the number of flips by 1 cnt++; //Flip the value of the next k positions of this position once for (int i = right; i < right + K; i++) { //And 1 to get their flipped values A[i] ^= 1; } } right++; } return cnt; }
Optimization ideas:
Through the above example, we can find that:
Conclusion 1: the reversal of the back interval will not affect the front elements. So you can use a greedy strategy,
Traverse from left to right, and flip it and the following K numbers when encountering each 0.
Conclusion 2: the result of an even number of turns of A[i] is A[i]; The result of flipping an odd number of times is A[i] ^ 1.
The main reason for our direct method timeout is that we actually flipped.
According to conclusion 2, the current state of position i is related to the number of times (parity) it is flipped by the previous K - 1 element.
We use the queue to simulate the sliding window, which means that the sub interval starting from which position in the previous K − 1 element has been flipped.
The sliding window slides from left to right. If the current position i needs to be flipped, the position is stored in the queue. When traversing to the new position J (J < i + k),
The number of elements in the queue represents the number of times i was flipped by the previous K - 1 elements.
When the I position is flipped an even number of times, if A[i] is 0, it is still 0 after flipping, and the current element needs to be flipped;
When the I position is flipped an odd number of times, if A[i] is 1, it is 0 after flipping, and the current element needs to be flipped.
Combining the above two points, we come to a conclusion that if len (que)% 2 = = a [i], the current element needs to be flipped.
When I + K > N, it indicates that the sub interval with size K needs to be flipped, but there are less than K remaining elements, so - 1 is returned.
Code implementation:
public int minKBitFlips(int[] A, int K) { //Define a double ended queue Deque<Integer> deque = new LinkedList<>(); //Gets the length of array A int n = A.length; //Define a counter to record the number of flips int cnt = 0; int right = 0; while(right < n) { if(deque.size() > 0 && i > deque.peek() + K - 1) { //It indicates that the right index position traversed at this time has exceeded the length of the queue header index plus K - 1, that is, the turnover of the queue deque header element at this time does not affect the right index element at this time deque.removeFirst(); } //According to the above conclusion if (deque.size() % 2 == A[i]) { //Note that A[i] needs to be flipped at this time: however, the number of remaining elements may be less than K if (i + K > A.length) { return -1; } //Otherwise, we do a flip operation cnt++; deque.add(i); } } return cnt; }
Question5: 992. Subarray of K different integers
Given A positive integer array A, if the number of different integers in A subarray of A is exactly K, the continuous and not necessarily different subarray of A is called A good subarray.
(for example, there are three different integers in [1,2,3,1,2]: 1, 2, and 3.)
Returns the number of good subarrays in A.
Example 1:
Input: A = [1,2,1,2,3], K = 2 Output: 7 Explanation: a subarray of exactly 2 different integers:[1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].
Example 2:
Input: A = [1,2,1,3,4], K = 3 Output: 3 Explanation: a subarray of exactly three different integers:[1,2,1,3], [2,1,3], [1,3,4].
Tips:
- 1 <= A.length <= 20000
- 1 <= A[i] <= A.length
- 1 <= K <= A.length
Resolution:
Important idea: number of subarrays containing K different integers = number of subarrays containing up to k different integers - number of subarrays containing up to K - 1 different integers!
Therefore, we only need to write a method for the number of subarrays containing up to X different integers
Since 1 < = a [i] < = a.length, we define an array of counts with a length of A.length + 1
We define two pointer variables, left and right, starting with 0, define a counter cnt, record the number of different integers, and a result set
while loop traversal condition: right < n
First, if the number of characters in the right index is 0: we will add 1 to the number of counters
Then we add 1 to the number of characters in the right index. If the number of different integers in [left,right] is greater than k, we recursively remove the value of the left index until cnt == K
Then we add 1 to the value of the right index
At this time, the number of combinations formed by [left,right] that satisfy the number of subarrays containing up to K different integers is: right - left
Code implementation:
//The number of subarrays containing exactly k different integers = the number of subarrays containing up to k different integers - the number of subarrays containing up to K - 1 different integers public int subarraysWithKDistinct(int[] A, int K) { return findMostSub(A,K) - findMostSub(A,K - 1); } //Use array to realize: optimize the following code: because the meaning of the question says 1 < = a [i] < = a.length private int findMostSub(int[] A, int k) { //Gets the length of the A array int n = A.length; //Define two pointer variables left,right int left = 0; int right = 0; //Defines the number of different integers recorded by the counter int cnt = 0; //Calculation result set int res = 0; //Define an array to record the number of occurrences of each value in array A int[] counts = new int[n + 1]; //Use the sliding window template to calculate the number of subarrays containing up to K different integers in array A while (right < n) { if (counts[A[right]] == 0) { //If A[right] is not included in counts, the number of counters will be increased by 1 when A[right] is added cnt++; } //Increase the number of occurrences of A[right] by 1 counts[A[right]]++; //The while loop is used here while (cnt > k) { //If the number of counters is greater than k at this time, we choose to recursively remove the value of the index position of the left pointer counts[A[left]]--; if (counts[A[left]] == 0) { //This indicates that the number of CNTs at this time is reduced by 1 cnt--; } left++; } right++; //At this time, the number of combinations formed by [left,right] that satisfy the number of subarrays containing up to K different integers is: right - left res += right - left; } return res; }
Question6: 1004. Maximum number of consecutive 1 III
Given an array A consisting of several 0 and 1, we can change up to K values from 0 to 1.
Returns the length of the longest (contiguous) subarray containing only 1.
Example 1:
Input: A = [1,1,1,0,0,0,1,1,1,1,0], K = 2 Output: 6 Explanation: [1,1,1,0,0,1,1,1,1,1,1] Bold numbers are flipped from 0 to 1, and the longest subarray length is 6.
Example 2:
Input: A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3 Output: 10 Explanation: [0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1] Bold numbers are flipped from 0 to 1, and the longest subarray length is 10.
Tips:
- 1 <= A.length <= 20000
- 0 <= K <= A.length
- A[i] is 0 or 1
Resolution:
This problem is solved using the above typical sliding window template:
Define two pointer variables: left = 0,right = 0;
Define a counter cnt to record the number of 0 transformed into 1
while loop traversal condition: right < n
If the value of A[right] is 0 at this time, we will increase the value of cnt counter by 1
If the value of cnt is greater than k at this time, it means that the number of transformations exceeds K. We choose to move the left pointer backward. If A[left] == 0, the value of cnt counter will be reduced by 1
Then add 1 to the right pointer
Finally, the while loop ends, and the value of right - left is the length of the longest (continuous) subarray at this time
Code implementation:
public int longestOnes(int[] A, int K) { int n = A.length; //Define two pointer variables left,right int left = 0,right = 0; int cnt = 0;//Define the counter cnt to record the number of 0 to 1 while(right < n) { if(A[right] == 0) { cnt++; } if(cnt > K) { if(A[left] == 0) { cnt--; } left++; } right++; } return right - left; } public int longestOnes(int[] nums, int k) { int n = nums.length; int left = 0; int right = 0; int res = 0; int cnt = 0; while (right < n) { //Add right to the result set first //If num [right] is 0 at this time, the cnt counter++ if (nums[right] == 0) ++cnt; while (cnt > k) { //Move the left boundary value and judge whether num [left] is 0 at this time if (nums[left] == 0) --cnt; left++; } //At this time, the [left, right] window value meets our requirements, and we choose to update the result set res = Math.max(res,right - left + 1); right++; } return res; }
Question7: 1052. Angry bookstore owner
Today, the bookstore owner has a store that is going to open for trial customers.length minutes. Every minute, some customers[i] enter the bookstore, and all these customers leave at the end of that minute.
At some point, bookstore owners get angry. If the bookstore owner is angry in the I minute, then grumpy[i] = 1, otherwise grumpy[i] = 0. When the bookstore owner is angry, the customers will be dissatisfied for that minute. If they are not angry, they are satisfied.
Bookstore owners know a secret skill that can restrain their emotions and keep themselves calm for X minutes, but they can only use it once.
Please return to this day of business, the maximum number of customers can be satisfied.
Example:
Input: customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3 Output: 16 Explanation: The bookstore owner kept calm in the last three minutes. Maximum number of satisfied customers = 1 + 1 + 1 + 1 + 7 + 5 = 16.
Tips:
- 1 <= X <= customers.length == grumpy.length <= 20000
- 0 <= customers[i] <= 1000
- 0 <= grumpy[i] <= 1
Resolution:
Code implementation:
public int maxSatisfied(int[] customers, int[] grumpy, int X) { int n = customers.length; //Define a variable: record the number of satisfied customers in this window int satisfied = 0; //We initialize the [0,X - 1] interval. The bookstore owner chooses to be calm, so everyone in the interval is satisfied for (int i = 0; i < X; i++) { satisfied += customers[i]; } for (int i = X; i < n; i++) { if (grumpy[i] == 0) { satisfied += customers[i]; } } //sliding window int right = X; int ans = satisfied; while (right < n) { //If right - X is not satisfied at this time, it breaks away from the calm window with length X, and the corresponding value will be removed from satisfied if (grumpy[right - X] == 1) { satisfied -= customers[right - X]; } //If the right index is not satisfied at this time, add a calm interval with length X and add its corresponding value to satisfied if (grumpy[right] == 1) { satisfied += customers[right]; } ans = Math.max(ans,satisfied); right++; } return ans; }
Question8: 1208. Make strings equal as much as possible
Give you two strings of the same length, s and t.
Changing the ith character in s to the ith character in t requires the overhead of | s[i] - t[i] | (the overhead may be 0), that is, the absolute value of the difference between the ASCII values of the two characters.
The maximum budget for the change string is maxCost. When converting strings, the total cost should be less than or equal to the budget, which also means that the conversion of strings may not be complete.
If you can convert the substring of s into its corresponding substring in t, the maximum length that can be converted is returned.
If there is no substring in s that can be converted to the corresponding substring in t, 0 is returned.
Example 1:
Input: s = "abcd", t = "bcdf", cost = 3 Output: 3 Explanation: s Medium "abc" Can become "bcd". The overhead is 3, so the maximum length is 3.
Example 2:
Input: s = "abcd", t = "cdef", cost = 3 Output: 1 Explanation: s If any character in t The cost of the corresponding characters in is 2. Therefore, the maximum length is 1.
Example 3:
Input: s = "abcd", t = "acde", cost = 0 Output: 1 Explanation: you can't make any changes, so the maximum length is 1.
Tips:
- 1 <= s.length, t.length <= 10^5
- 0 <= maxCost <= 10^6
- Both s and t contain only lowercase English letters.
Resolution:
This problem can be solved by using the general template of sliding window!!!
Code implementation:
public int equalSubstring(String s, String t, int maxCost) { //Gets the length of the s string, n int n = s.length(); //Define an array vals: where vals[i] represents the cost of converting s[i] into t[i] int[] vals = new int[n]; for (int i = 0; i < n; i++) { vals[i] = Math.abs(s.charAt(i) - t.charAt(i)); } //Defines the left and right pointers of the window that satisfies the longest substring within the overhead int left = 0; int right = 0; int cost = 0; //Record expenses spent while (right < n) { //Add the cost value of the right index to the cost result set cost += vals[right]; if (cost > maxCost) { //If the cost exceeds maxCost at this time, we choose to move the left index of the window one bit to the right cost -= vals[left]; left++; } //Then move the value of the right index one bit to the right right++; } //The value of the last right - left is the longest length of the conversion return right - left; }
Question9: 1423. Maximum points available
Several cards are arranged in a row, and each card has a corresponding point. The number of points is given by the integer array cardPoints.
For each action, you can take a card from the beginning or end of the line. In the end, you must take exactly k cards.
Your points are the sum of all the cards you get.
Give you an integer array cardPoints and integer k, please return the maximum number of points you can get.
Example 1:
Input: cardPoints = [1,2,3,4,5,6,1], k = 3 Output: 12 Explanation: the first action, no matter which card you take, your point is always 1. However, taking the rightmost card first will maximize your points available. The best strategy is to take the three cards on the right, and the final point is 1 + 6 + 5 = 12 .
Example 2:
Input: cardPoints = [2,2,2], k = 2 Output: 4 Explanation: no matter which two cards you pick up, the points you can get are always 4.
Example 3:
Input: cardPoints = [9,7,7,9,7,7,9], k = 7 Output: 55 Explanation: you must pick up all cards. The points you can get are the sum of the points of all cards.
Example 4:
Input: cardPoints = [1,1000,1], k = 1 Output: 1 Explanation: you can't get the card in the middle, so the maximum point you can get is 1.
Example 5:
Input: cardPoints = [1,79,80,1,1,1,200,1], k = 3 Output: 202
Tips:
- 1 <= cardPoints.length <= 10^5
- 1 <= cardPoints[i] <= 10^4
- 1 <= k <= cardPoints.length
Resolution:
The sliding window of this question is similar to the question of the angry bookstore owner above
We define two windows: left_sum and right_sum
Because we need to get k cards: so we start left_sum is the sum of [0,k -1], right_sum is null
Then we define left = k -1,right = n -1 in turn
We left_sum subtracts the value of the left index at this time, and then adds the value of the right index to get a new card taking method
Then update the result set
Code implementation:
public int maxScore(int[] cardPoints, int k) { //Gets the length of cardPoints int n = cardPoints.length; //Define left_sum,right_sum int left_sum = 0; int right_sum = 0; //left_sum and right_sum is initialized. There is a value of k in the left window and no value in the right window for (int i = 0; i < k; i++) { left_sum += cardPoints[i]; } //Define maxSum result set int maxSum = left_sum; int left = k - 1; int right = n - 1; while (left >= 0) { left_sum -= cardPoints[left--]; right_sum += cardPoints[right--]; maxSum = Math.max(maxSum,left_sum + right_sum); } return maxSum; }