Sliding window -- double pointer idea with the same direction

Posted by sidney on Mon, 20 Dec 2021 23:26:00 +0100

The general idea is as follows:

Given a sequence, define two pointers left and right, and define the measurement index F before the interval [left,right], such as interval sum, product and others according to the meaning of the question. At the beginning, left=right=0, calculate the index F. left remains unchanged first, right moves to the right, and the value of F is updated. When f meets certain conditions, left moves to the right, which is equivalent to that the interval becomes smaller, and the value of F is updated. If f always meets the meaning of the question, left always moves to the right. If f does not meet the meaning of the question, left remains unchanged and continues to move the right position. In this way, it is equivalent to a sliding window traversing the whole sequence. In the whole process, when the interval [left,right] is found, the process can be recorded and the extreme value can be finally obtained.

Let's have some exercises

/**
 *Given an array containing n positive integers and a positive integer target.
 *
 *Find out the continuous subarray [numsl, numsl + 1,..., numsr-1, numsr] with the smallest length satisfying its sum ≥ target in the array,
 *And returns its length. If there is no eligible subarray, 0 is returned.
 *
 * */
public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int right = 0;
        int sum = 0;
        int min = Integer.MAX_VALUE;
        // If the sum is less than target, 0 is returned directly
        int total = Arrays.stream(nums).sum();
        if (total < target) return 0;
        // Double pointer right pointer keeps exploring to the right to find the qualified position
        // At this point, the left pointer attempts to search for a larger position to the right
        for (right=0; right<nums.length; right++) {
            sum = sum + nums[right];
            while (sum >= target) {
                min = Math.min(min, right-left+1);
                sum = sum - nums[left];
                left++;
            }
        }
        return min;
    }
/**
 *Given a positive integer array nums and integer k, please find out the number of consecutive sub arrays in the array whose product is less than k.
 * */
public int numSubarrayProductLessThanK(int[] nums, int k) {
        int left = 0;
        int right = 0;
        int acc = 1;
        int cnt = 0;
        for (right=0; right<nums.length; right++) {
            acc = acc * nums[right];
            while (acc >= k && left <= right) {
                acc = acc / nums[left];
                left++;
            }
            if (left <= right) {
                cnt = cnt + (right - left + 1);
            }
        }
        return cnt;
    }
/**
 *Given a string s, please find the length of the longest consecutive substring that does not contain duplicate characters.
 *s consists of English letters, numbers, symbols and spaces
 * */
public int lengthOfLongestSubstring(String s) {
        int max = 0;
        Map<Character, Integer> map = new HashMap<>();
        int left = 0;
        int right = 0;
        for ( ; right < s.length(); right++) {
            map.put(s.charAt(right), map.getOrDefault(s.charAt(right), 0) + 1);
            while (!allLessThanOne(map) && left <= right) {
                map.put(s.charAt(left), map.getOrDefault(s.charAt(left), 0) - 1);
                left++;
            }
            max = Math.max(max, right - left + 1);
        }
        return max;
    }

    private boolean allLessThanOne(Map<Character, Integer> map) {
        return map.values().stream().filter(num -> num > 1).count() == 0;
    }
/**
 *Give two strings s and t. Returns the shortest substring of all characters containing T in s
 *If there is no qualified substring in s, the empty string '' is returned
 *If there are multiple qualified substrings in s, any one is returned
 *Note: for repeated characters in T, the number of characters in the substring we are looking for must not be less than the number of characters in t
 *s and t consist of English letters
 * */
public String minWindow(String s, String t) {
        if (s.length() < t.length()) return "";
        Map<Character, Integer> map = new HashMap<>();
        for (char ch: t.toCharArray()) {
            map.put(ch, map.getOrDefault(ch, 0) + 1);
        }
        int left = 0;
        int right = 0;
        int minLength = Integer.MAX_VALUE;
        int minLeft = 0, minRight = 0;
        for ( ; right < s.length(); right++) {
            map.put(s.charAt(right), map.getOrDefault(s.charAt(right), 0) - 1);
            while (allLessEqualThanOne(map) && left <= right) {
                if ((right-left) < minLength) {
                    minLeft = left;
                    minRight = right;
                    minLength = minRight - minLeft;
                }
                map.put(s.charAt(left), map.getOrDefault(s.charAt(left), 0) + 1);
                left++;
            }
        }
        return minLength == Integer.MAX_VALUE ? "" : s.substring(minLeft, minRight + 1);
    }

    private boolean allLessEqualThanOne(Map<Character, Integer> map) {
        return map.values().stream().filter(num -> num >= 1).count() == 0;
    }

Topics: Algorithm Double Pointer