Sliding Window - LeetCode

264 阅读2分钟

The sliding windows technique can be used as starting from i=0 and keep looping till we find the t string to be matched and present in s string, First we acquire the next character from strings and if we found required less than or equal from the s string and from the t string we increase matchcount and We keep releasing and character by checking whether we got exact count of t chars found in s string in another loop and yes keep updating if minimum length between j and i , If we lost some character while releasing we update and reduce the required frequency/number of character from s stored in hashmap than the required t string character frequency and so on. At worst only 2 characters will be checked.

/* 滑动窗口算法框架 Go Version */ 
void slidingWindow(string s, string t) {
    unordered_map<char, int> need, window;
    for (char c : t) need[c]++;

    int left = 0, right = 0;
    int valid = 0;
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        /*** debug 输出的位置 ***/
        printf("window: [%d, %d)\n", left, right);
        /********************/

        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

Q****76. Minimum Window Substring

Given two strings s and t, return the minimum window in s which will contain all the characters in t . If there is no such window in s that covers all characters in t, return the empty string "".

Note that If there is such a window, it is guaranteed that there will always be only one unique minimum window in s.

Example 1:

Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"

Example 2:

Input: s = "a", t = "a"
Output: "a"

Constraints:

  • 1 <= s.length, t.length <= 105
  • s and t consist of English letters.

Follow up: Could you find an algorithm that runs in O(n) time?

解法及注释

class Solution {
    public String minWindow(String s, String t) {
        if(s == null || s.length() == 0 || t == null || t.length() == 0)
            return "";
        
        //Step 1: initialize map to keep needed chars and window chars
        Map<Character, Integer> need = new HashMap();
        Map<Character, Integer> window = new HashMap();
        
        //Step 2: fill all the needed chars
        for(int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            need.put(c, need.getOrDefault(c, 0) + 1);
        }
        
        int left = 0, right = 0, matched = 0;
        int start = 0, end = 0, min = Integer.MAX_VALUE;
        char c;
        
        //Step 3: loop through the string
        while(right < s.length()) {
            c = s.charAt(right);
            right++;
            
            //Step 3.1  put it into window
            window.put(c, window.getOrDefault(c, 0) + 1);
            //Step 3.2  add c inside need map
            if(need.containsKey(c)) {   
                //increase matched if needed and still pending for increment to window
                if(window.get(c) <= need.get(c))
                    matched++;
            }
                 
            //Step 3.3 if all matched chars are added try shrink the window
            while(matched == t.length() && left < right) {
                if(right - left < min) {
                    min = right - left;
                    start = left;
                    end = right;
                }
                
                //Step 3.4  start to shrink from left side
                c = s.charAt(left);
                left++;
                window.put(c, window.get(c) - 1);
                
                //Step 3.5  bypass if c is not included in the need map
                if(need.containsKey(c)) {
                    //if c is fully matched, then left moving will reduce one matched 
                    //jump out the loop if matched minus by one
                    if(window.get(c) < need.get(c))
                        matched--;
                }
            }       
        }  
        
        if(min == Integer.MAX_VALUE)
            return "";
        return s.substring(start, end);
    }
}

Q****239. Sliding Window Maximum

You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the max sliding window.

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation: 
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 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       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

Example 2:

Input: nums = [1], k = 1
Output: [1]

Example 3:

Input: nums = [1,-1], k = 1
Output: [1,-1]

Example 4:

Input: nums = [9,11], k = 2
Output: [11]

Example 5:

Input: nums = [4,-2], k = 2
Output: [4]

Constraints:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

解法及注释

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int len = nums.length;
        if(len == 0 || k == 0)
            return new int[0];
        
        int[] res = new int[len - k + 1];
        //record the position in deque
        Deque<Integer> deque = new ArrayDeque();
        for(int i = 0; i < len; ++i) {
            //remove unnecessary elements in deque
            while(deque.size() > 0 && deque.peekFirst() <= i - k)
                deque.pollFirst();
            
            while(deque.size() > 0 && nums[deque.peekLast()] < nums[i])
                deque.pollLast();
            
            deque.offerLast(i);
            //add into res
            if(i >= k - 1)
                res[i - k + 1] = nums[deque.peekFirst()];
            
        }
        return res;
    }
}

Q****480. Sliding Window Median

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples:

[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array.

For example,
Given 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, return the median sliding window as [1,-1,-1,3,5,6].

Note:
You may assume k is always valid, ie: k is always smaller than input array's size for non-empty array.
Answers within 10^-5 of the actual value will be accepted as correct.

解法及注释

class Solution {
    PriorityQueue<Integer> maxHeap = new PriorityQueue(Collections.reverseOrder());
    PriorityQueue<Integer> minHeap = new PriorityQueue();
    
    public double[] medianSlidingWindow(int[] nums, int k) {
        int len = nums.length;
        if(len == 0 || k == 0)
            return new double[0];
        
        double[] res = new double[len - k + 1];
        for(int i = 0; i < len; i++) {
            if(maxHeap.size() == 0 || maxHeap.peek() >= nums[i]) 
                maxHeap.add(nums[i]);
            else
                minHeap.add(nums[i]);
            
            rebalanceHeaps();
            
            if(i - k + 1 >= 0) {
                if(maxHeap.size() == minHeap.size()) {
                    res[i - k + 1] = maxHeap.peek() / 2.0 + minHeap.peek() / 2.0;
                } else {
                    res[i - k + 1] = maxHeap.peek();
                }
                int removeElement = nums[i - k + 1];
                if(removeElement <= maxHeap.peek()) {
                    maxHeap.remove(removeElement);
                } else 
                    minHeap.remove(removeElement);
            }
            rebalanceHeaps();
        }
        return res;
    }
    
    private void rebalanceHeaps() {
        if(maxHeap.size() > minHeap.size() + 1)
            minHeap.add(maxHeap.poll());
        else if(maxHeap.size() < minHeap.size()) {
            maxHeap.add(minHeap.poll());
        }
    }
}