[Leetcode][sliding window][713/2958/2962/992/2444]

172 阅读6分钟

713.SubarrayProductLessThanK

Description:

Given an array of integers nums and an integer k, return the number of contiguous subarrays where the product of all the elements in the subarray is strictly less than k.
1 <= nums[i] <= 1000

Example 1:

Input: nums = [10,5,2,6], k = 100
Output: 8
Explanation: The 8 subarrays that have product less than 100 are:
[10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]
Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

Solution: Java Solution for Subarray Products Less Than K Problem

The above link introduces a solution with sliding window. Let's discuss about the summation formula: count += right - left + 1:
    if current sliding window is [10, 5] and the cursor is moving to 2, 10 * 5 * 2 < 100, so the sliding window will become [10, 5, 2]. How many subarrays have been added now? [10,5,2] [5,2] and [2], we can imagine there are three people, and 2 handshake with 10 [10,5,2] and 5 [5,2] plus itself [2]. That's how many points there are in between right - left + 1.

fun numSubarrayProductLessThanK(nums: IntArray, k: Int): Int {
    // since all number are positive, 
    // if we do not judge K <= 1, the product will always greater than k and left will move to out of array bound.
    if (k <= 1) {
        return 0
    }
    var product = 1
    var left = 0
    var result = 0

    for (right in nums.indices) {
        product *= nums[right]
        // when product < k, the worst situation is left = right + 1, product = 1
        while (product >= k) {
            product /= nums[left]
            left++
        }
        // calculate the subarrays number
        result += right - left + 1
    }

    return result
}

2958.Length of Longest Subarray With at Most K Frequency

Description:

You are given an integer array nums and an integer k.

The frequency of an element x is the number of times it occurs in an array.

An array is called good if the frequency of each element in this array is less than or equal to k.

Return the length of the longest good subarray of nums .

subarray is a contiguous non-empty sequence of elements within an array.

Example 1:

Input: nums = [1,2,3,1,2,3,1,2], k = 2
Output: 6
Explanation: The longest possible good subarray is [1,2,3,1,2,3] since the values 1, 2, and 3 occur at most twice in this subarray. Note that the subarrays [2,3,1,2,3,1] and [3,1,2,3,1,2] are also good.
It can be shown that there are no good subarrays with length more than 6.

We can use a sliding window to effciently keep track of the frequency of elements within a subarray.

Initialize two pointers, left and right, to mark the left and right boundaries of the current subarray. Then, Initialize a map to store the frequency of elements with in the current subarray. Moving right pointer until the number in right pointer has appeared more than k times. It's time for moving left pointer until the appear times of the number in right pointer drop into less than or equal k times. Update the maximum length of the good subbarry if necessary.

// sliding window (runtime Beats 86.36%)
fun maxSubarrayLength(nums: IntArray, k: Int): Int {
    val map = mutableMapOf<Int, Int>()
    var left = 0
    var right = 0
    var maxLength = 0
    val n = nums.size
    // end point
    while (right < n) {
        // record frequency of current number
        map[nums[right]] = (map[nums[right]]?:0) + 1
        // current right number is less than k, it is possible to have a longer length.
        if (map[nums[right]]!! <= k) {
            maxLength = max(maxLength, right - left + 1)
        } else {
            // move left point until right is less or equals k
            while (map[nums[right]]!! > k) {
                map[nums[left]] = map[nums[left]]!! - 1
                left++
            }
        }
        // move to next one
        right++
    }
    return maxLength
}

2962.Count Subarrays Where Max Element Appears at Least K Times

Description:

You are given an integer array nums and a positive integer k.

Return the number of subarrays where the maximum element of nums appears at least k times in that subarray.

subarray is a contiguous sequence of elements within an array.

Example 1:

Input: nums = [1,3,2,3,3], k = 2
Output: 6
Explanation: The subarrays that contain the element 3 at least 2 times are: [1,3,2,3], [1,3,2,3,3], [3,2,3], [3,2,3,3], [2,3,3] and [3,3].

Solution:

example: [1,3,2,3,3]

  • Fist of all, we need to find out the max number of the list.(3)
  • Then, we find the kth max number, [1,3,2,3,3], and right point stop here.
  • In addition, we find the kth max number before right point,[1,3,2,3,3], we let left point stop here. so use right and left point, we can calculate the subarrays is 2 (left point + 1, [1, 3, 2, 3] and [3, 2, 3]).
  • What's more, moving right point to the next, if the counts of max number are big than k, we move left point to the next max number.[1,3,2,3,3]. Now, the number of added subarray is 4 (left + 1, [1,3,2,3,3], [3,2,3,3], [2,3,3], [3,3]).
  • In a nutshell, we just control the left and right point containing k max number, left point is the first max number and each time we move right point, the result add left + 1.
fun countSubarrays(nums: IntArray, k: Int): Long {
    var max = nums[0]
    // find max number
    nums.forEach {
        max = max(max, it)
    }
    var times = 0
    var right = 0
    var left = 0
    var result = 0L
    // end condition
    while (right < nums.size) {
        if (nums[right] == max) {
            times++
        }
        // move right point to find next max number
        if (times < k) {
            right++
        } else {
            // current left to right contian k + 1 max number
            if (times > k) {
                left++
                times--
            }
            // find the next max number
            while (nums[left] != max) {
                left++
            }
            // current left to right contain k max number, 
            // every index less and equal than left can form a good subarray.
            result += left + 1
            // move to next
            right++
        }
    }
    return result
}

992.Subarrays with K Different Integers

Descrption: Given an integer array nums and an integer k, return the number of good subarrays of nums.

good array is an array where the number of different integers in that array is exactly k.

  • For example, [1,2,3,1,2] has 3 different integers: 12, and 3.

subarray is a contiguous part of an array.

Example 1:

Input: nums = [1,2,1,2,3], k = 2
Output: 7
Explanation: Subarrays formed with exactly 2 different integers: [1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2]

Solution: Editorial Solution

The offical answer is a really good method.

Here, we will learn the editorial solution approach 2. Let's take [1,2,1,2,3] and k = 2 as example. The most crucial part of the approach is that if there are duplicates of nums[left] within the current window, we need to keep shirinking the window from the left side until the frequency of nums[left] is zero. Because we need to maintain the correct count of distinct elements within the window. If we don't do this, then we can't decide how to move left point.

  • left = 0, right = 0, subarray is [1], distinct number < 2, countine.
  • left = 0, right = 1, subarray is [1,2], distinct number = 2, result = 0+1, countine.
  • left = 0, right = 2, subarray is [1,2,1], distinct number = 2. How should we move the point? first, move the left point, we do not want every nubmer in the subarray has multi counts. we want subarray like: [1,2,2,2,2,2], [1,2], no like: [1,2,2,1], [1,1,1,1,2,2,2]. So, we should move left point to 1, current subarray is [2,1], and counts contained in subarray is 1 (because, we have [2,1], we can make up a good subarray [1] + [2,1], what number does the contained have, then how many subarray it can form). continue
  • left = 1, right = 2, subarray is [2,1], contained count = 1, result += countainedCount([1,2,1]) + 1 ([2,1], the right point add the one). move right point.
  • left = 1, right = 3, as the same as before, we should move left to next. and containedCount = 2 (1 and 2 [1,2,1,2,3]). and result += 2([1,2,1,2], [2,1,2]) + 1([1,2]).
fun subarraysWithDistinct(nums: IntArray, k: Int): Int {
    val length = nums.size
    val windowNums = mutableMapOf<Int, Int>()
    var result = 0
    var left = 0
    var right = 0
    windowNums[nums[right]] = (windowNums[nums[right]]?:0) + 1
    var numContainedFrontWindow = 0
    while (right < length) {
        if (windowNums.size < k) {
            // distinct numbers less than k, move right point
            right++
            if (right < length) {
                windowNums[nums[right]] = (windowNums[nums[right]] ?: 0) + 1
            }
        } else if (windowNums.size > k) {
            // distinct numbers grate than k, move left point
            windowNums[nums[left]] = windowNums[nums[left]]!! - 1
            if (windowNums[nums[left]] == 0) {
                windowNums.remove(nums[left])
            }
            left++
            // new number is involved, the left point must be the only one in subarray.
            // so, every subarray contain left point can't form a good subarray with the right point.
            // reset the counter.
            numContainedFrontWindow = 0
        } else {
            // distinct numbers equal k
            if (windowNums[nums[left]]!! <= 1) {
                // beyond left point, there is the only one
                // each one can form a good subarray.
                result += numContainedFrontWindow + 1
                right++
                if (right < length) {
                    windowNums[nums[right]] = (windowNums[nums[right]] ?: 0) + 1
                }
            } else {
                // beyond left point, there are more same number as left point{the latest right point}.
                numContainedFrontWindow++
                windowNums[nums[left]] = windowNums[nums[left]]!! - 1
                if (windowNums[nums[left]] == 0) {
                    windowNums.remove(nums[left])
                }
                left++
            }
        }
    }
    return result
}

2444.Count Subarrays With Fixed Bounds You are given an integer array nums and two integers minK and maxK.

fixed-bound subarray of nums is a subarray that satisfies the following conditions:

  • The minimum value in the subarray is equal to minK.
  • The maximum value in the subarray is equal to maxK.

Return the number of fixed-bound subarrays.

subarray is a contiguous part of an array.

Example 1:

Input: nums = [1,3,5,2,7,5], minK = 1, maxK = 5
Output: 2
Explanation: The fixed-bound subarrays are [1,3,5] and [1,3,5,2].

Example 2:

Input: nums = [1,1,1,1], minK = 1, maxK = 1
Output: 10
Explanation: Every subarray of nums is a fixed-bound subarray. There are 10 possible subarrays.

Solution: 98.43% Easy Solution with explanation

fun countSubarrays(nums: IntArray, minK: Int, maxK: Int): Long {
    var res = 0L
    var bad = -1
    var left = -1
    var right = -1

    for (i in nums.indices) {
        if (nums[i] !in minK..maxK) {
            bad = i
        }

        if (nums[i] == minK) {
            left = i
        }

        if (nums[i] == maxK) {
            right = i
        }
        
        // if right < left, bad must > right
        res += max(0, min(left, right) - bad)
    }

    return res
}