Sliding Window Algorithm Questions

LeetCode 424. Longest Repeating Character Replacement

Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at most k times. Find the length of a longest substring containing all repeating letters you can get after performing the above operations.

 

Algorithm: For a given window, always keep the letter that appears the most and replace other letters. This minimizes replacement times.  For a window of [i, j] with length L = j - i + 1, as long as L - maxFrequency <= k, we can keep extending this window's right bound by 1. As soon as L - maxFrequency > k, we know that we've just reached the limit of all windows that start at index i and the max value of all these windows is L - 1(including the current letter requires k + 1 replacements).  At this point, update the current max value then move forward the left bound of possible windows to i + 1 and decrement the frequency of letter at i by 1. 

 

When calculating the max frequency in a given window, we don't need to go through the entire frequency array. Since any possible new max frequency can only come from either the new frequency of the newly added letter or the previous max frequency, we just need to compare these two.

 

class Solution {
    public int characterReplacement(String s, int k) {
        int[] freq = new int[26];
        int start = 0, end = 0, maxFreq = 0, maxLen = 0;
        while(end < s.length()) {
            freq[s.charAt(end) - 'A']++;
            maxFreq = Math.max(maxFreq, freq[s.charAt(end) - 'A']);
            int len = end - start + 1;
            if(len - maxFreq > k) {     
                maxLen = Math.max(maxLen, len - 1);
                freq[s.charAt(start) - 'A']--;
                start++;
            }
            end++;
        }
        return Math.max(maxLen, end - start);
    }
}

 

LeetCode 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.

 

Algorithm: Preprocess string p to get a character frequency difference map. Take a window of size p.length(), and slide it from left to right through s. Each slide has 1 add and 1 deletion operation to the diff map. When a character's diff becomes 0, remove this key from diff map. When the entire diff map is empty, the current window is one anagram of p. Since it is a diff map, each time we add a character, we decrement its count by 1, representing the difference is getting smaller; each time we remove a character, we increment its count by 1, representing the difference is getting bigger.

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<>();
        if(p.length() > s.length()) {
            return res;
        }
        Map<Character, Integer> diff = new HashMap<>();
        for(int i = 0; i < p.length(); i++) {
            diff.put(p.charAt(i), diff.getOrDefault(p.charAt(i), 0) + 1);
        }
        for(int i = 0; i < p.length(); i++) {
            diff.put(s.charAt(i), diff.getOrDefault(s.charAt(i), 0) - 1);
            if(diff.get(s.charAt(i)) == 0) {
                diff.remove(s.charAt(i));
            }
        }
        if(diff.size() == 0) {
            res.add(0);
        }
        for(int i = p.length(); i < s.length(); i++) {
            char start = s.charAt(i - p.length()), end = s.charAt(i);
            diff.put(start, diff.getOrDefault(start, 0) + 1);
            if(diff.get(start) == 0) {
                diff.remove(start);
            }
            diff.put(end, diff.getOrDefault(end, 0) - 1);
            if(diff.get(end) == 0) {
                diff.remove(end);
            }
            if(diff.size() == 0) {
                res.add(i - p.length() + 1);
            }
        }
        return res;        
    }
}

 

LeetCode 76. Minimum Window Substring

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).

Example:

Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"

Note:

  • If there is no such window in S that covers all characters in T, return the empty string "".
  • If there is such window, you are guaranteed that there will always be only one unique minimum window in S.

 

Similarly with Find All Anagrams in a String, we construct a difference map from T. Finding a minimum window that contains all the characters  of T is quite different with finding an anagram of T. The latter has a fixed window size and does not allow characters that do not exist in T. It does not allow extra characters than needed. A minimum window allow both. For example, if S = "ABBDF" and T = "ABF", then the entire S contains T, but there is no substrings that is an anagram of T. 

 

Algorithm

1. construct a difference map from T; Use a counter variable to track if a given window contains all characters from T. counter is initialized to be the size of the difference map. counter-- means for a particular character from T, we've matched all its occurences and counters++ means we can't match all the occurences of a particular character from T.

2. Keep a sliding window. As long as counter != 0, keep extending the right bound and update the diff map: (a) if the current character does not exist in T, ignore; (b) otherwise update the diff map. If the new count of this character is 0, counter--.

3. When counter == 0, the current sliding window contains all characters from T; update min length and keep contracting the left bound if possible: (a) if the current character does not exist in T, ignore; (b) otherwise update the diff map. If the new count of this character is > 0, counter++.

 

class Solution {
    public String minWindow(String s, String t) {
        if(s.length() < t.length() || t.length() == 0) return "";
        
        Map<Character, Integer> diff = new HashMap<>();
        for(int i = 0; i < t.length(); i++) {
            diff.put(t.charAt(i), diff.getOrDefault(t.charAt(i), 0) + 1);
        }
        
        int left = 0, right = 0, minLen = Integer.MAX_VALUE, minLeft = 0, minRight = 0, counter = diff.size();
        
        while(right < s.length()) {
            char addChar = s.charAt(right);
            if(diff.containsKey(addChar)) {
                int currCount = diff.get(addChar);
                diff.put(addChar, currCount - 1);
                if(currCount == 1) {
                    counter--;
                }
            }
            while(counter == 0) {
                if(right - left + 1 < minLen) {
                    minLen = right - left + 1;
                    minLeft = left;
                    minRight = right;
                }
                char delChar = s.charAt(left);
                if(diff.containsKey(delChar)) {
                    int currCount = diff.get(delChar);
                    diff.put(delChar, currCount + 1);
                    if(currCount == 0) {
                        counter++;
                    }
                }
                left++;
            }
            right++;
        }   
        
        return minLen == Integer.MAX_VALUE ? "" : s.substring(minLeft, minRight + 1);
    }
}

 

 

LeetCode 727. Minimum Window Subsequence

Given strings S and T, find the minimum (contiguous) substring W of S, so that T is a subsequence of W.

If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple such minimum-length windows, return the one with the left-most starting index.

Example 1:

Input: 
S = "abcdebdde", T = "bde"
Output: "bcde"
Explanation: 
"bcde" is the answer because it occurs before "bdde" which has the same length.
"deb" is not a smaller window because the elements of T in the window must occur in order.

 

Note:

  • All the strings in the input will only contain lowercase letters.
  • The length of S will be in the range [1, 20000].
  • The length of T will be in the range [1, 100].

 

转载于:https://www.cnblogs.com/lz87/p/10699614.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值