Length of Longest Subarray With at Most K Frequency

Updated on 04 June, 2025
Length of Longest Subarray With at Most K Frequency header image

Problem Statement

In this problem, we're provided with an integer array nums and an integer k. The objective is to identify the longest contiguous subarray of nums such that the frequency of each element within that subarray does not exceed k, where the frequency is defined as the number of occurrences of an element within the array. We need to return the length of this longest "good" subarray. A subarray is a contiguous part of the original array and all elements must satisfy the frequency condition to qualify as "good".

Examples

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.

Example 2

Input:

nums = [1,2,1,2,1,2,1,2], k = 1

Output:

2

Explanation:

The longest possible good subarray is [1,2] since the values 1 and 2 occur at most once in this subarray. Note that the subarray [2,1] is also good.
It can be shown that there are no good subarrays with length more than 2.

Example 3

Input:

nums = [5,5,5,5,5,5,5], k = 4

Output:

4

Explanation:

The longest possible good subarray is [5,5,5,5] since the value 5 occurs 4 times in this subarray.
It can be shown that there are no good subarrays with length more than 4.

Constraints

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

Approach and Intuition

To solve this problem efficiently, the concept of a sliding window combined with a frequency map can be effectively applied. Here's a step-by-step plan:

  1. Initialize two pointers to represent the current window of the array. These are usually termed as the start and end pointers.
  2. Use a hashmap (or dictionary) to keep track of the frequency of each element within the current window.
  3. Expand the end pointer to include elements in the window until the condition is violated (i.e., the frequency of some element in the window exceeds k).
  4. Once the condition is violated, start moving the start pointer to the right to reduce the size of the window until the subarray becomes "good" again (i.e., the frequency of all elements are within the limit set by k).
  5. The size of the window at each valid state (where all frequencies are ≤ k) can be considered as a potential answer. Always update and record the maximum size obtained.
  6. Continue this until the end pointer has traversed the entire array.
  • Example walkthrough with nums = [1,2,3,1,2,3,1,2], k = 2:
    • Increase the window size by moving end until you exceed k with any number.
    • Initially, the window grows to encompass 1,2,3,1,2,3 before any frequency exceeds k.
    • At this point, the largest good window has a length of 6.
    • Adjust start and end trying to find a potentially larger good subarray, but none can be found in this instance.

This approach ensures that each element is processed a limited number of times, making the sliding window technique efficient for this problem. The use of the frequency hashmap enables quick checks and updates for the conditions described.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    int longestUniformSubarray(vector<int>& elements, int threshold) {
        int len = elements.size(); 
        unordered_map<int, int> countMap; 
        int left = 0;
        int excessCount = 0;
        
        for (int right = 0; right < len; right++) {
            countMap[elements[right]]++;
            if (countMap[elements[right]] == threshold + 1) {
                excessCount++;
            }
            if (excessCount > 0) {
                countMap[elements[left]]--;
                if (countMap[elements[left]] == threshold) {
                    excessCount--;
                }
                left++;
            }
        }
        return len - left;
    }
};

You're aiming to compute the length of the longest subarray wherein each element appears at most k times within the array. By establishing a window of potential valid subarrays through incrementally adjusting the left and right pointers, the solution makes efficient use of space and runs competitively fast. Here's how the code in C++ manages this:

  • Maintain a hashmap to keep track of the frequency of each element over the current window defined by left and right pointers.
  • Incrementally explore the array using the right pointer. As each element frequency increases, update the count in this map.
  • When any element exceeds the allowed threshold frequency (k), it is marked as exceeding by using an excessCount.
  • Use the left pointer to shrink the window from the left, decrementing the count of the element at left in the map, until the excessCount becomes zero again—indicating all elements within the window do not exceed the threshold.
  • The size of the window at the end of this process (when right reaches the end of the array) shows the largest such window encountered that satisfies the condition.

This approach primarily focuses on managing and adjusting the window of "valid" subarrays until the optimal solution (longest valid subarray) is found while updating the frequency map accordingly. It strikes a good balance between time complexity (efficient traversal) and space complexity (minimal space usage beyond the original array size).

java
class Solution {
    public int maxLengthSubarray(int[] array, int target) {
        int size = array.length;
        Map<Integer, Integer> countMap = new HashMap();
        int begin = 0;
        int excessElements = 0;

        for (int end = 0; end < size; end++) {
            countMap.put(array[end], countMap.getOrDefault(array[end], 0) + 1);
            if (countMap.get(array[end]) == target + 1) {
                excessElements++;
            }
            if (excessElements > 0) {
                countMap.put(array[begin], countMap.get(array[begin]) - 1);
                if (countMap.get(array[begin]) == target) {
                    excessElements--;
                }
                begin++;
            }
        }
        return size - begin;
    }
}

The provided Java solution is designed to find the length of the longest subarray where the frequency of each element does not exceed a specified value, target. The approach uses a sliding window technique along with a hashmap to efficiently track the frequency of each element in the current window. Here's a concise summary of how the solution is implemented:

  • Initialize a hashmap countMap to store the frequency of elements within the current window.
  • Use two pointers, begin and end, to represent the current window's start and end positions respectively.
  • Iterate through the array using the end pointer. For each element at position end, update its frequency in countMap.
  • Check if the updated frequency exceeds target by one (i.e., target + 1). If so, increment a counter excessElements that tracks the number of elements whose frequency is beyond the allowed count.
  • If excessElements is greater than zero, it's necessary to shrink the window from the beginning by moving the begin pointer right. During this, decrease the frequency of the element at the begin position, and if its frequency drops back to target, decrement excessElements.
  • Continue expanding and contracting the window until end reaches the end of the array.
  • Finally, return the maximum length of the subarray that meets the condition, which is calculated using the difference between the size of the array and the position of begin.

This method ensures that the subarray found is the longest possible where no element appears more than target times, achieved through an optimal O(n) complexity where n is the size of the array.

python
class Solution:
    def longestSubarrayLength(self, values: List[int], threshold: int) -> int:
        length = len(values)
        count_map = Counter()
        begin = 0
        count_exceed_threshold = 0
        for finish in range(length):
            count_map[values[finish]] += 1
            if count_map[values[finish]] == threshold + 1:
                count_exceed_threshold += 1
            if count_exceed_threshold:
                count_map[values[begin]] -= 1
                if count_map[values[begin]] == threshold:
                    count_exceed_threshold -= 1
                begin += 1
        return length - begin

This Python 3 solution addresses the problem of finding the length of the longest subarray in which the frequency of any element does not exceed a specified threshold, k. The function longestSubarrayLength accepts two parameters: values, a list of integers, and threshold, an integer representing the maximum allowable frequency for any element within the subarray.

Let's break down the solution:

  • Initialize a length variable length to the length of the values list.
  • Create a count_map to keep track of the frequency of elements.
  • Set begin, a pointer to the start of the window, to zero and count_exceed_threshold, a counter for when an element's frequency exceeds the threshold, to zero.
  • Use a loop to traverse through the values list and increment the frequency of each element in count_map.
  • If the frequency of the currently processed element exceeds threshold, increment count_exceed_threshold.
  • If any frequency exceeds the set threshold, decrease the frequency of the element at the begin position and possibly adjust count_exceed_threshold if the frequency goes back down to the threshold. Then increment begin to narrow the window.
  • The desired length of the longest subarray is found by calculating length - begin at the end of the loop.

This approach efficiently finds the solution using a sliding window technique to adjust the size of the potential subarray based on the frequency conditions provided.

Comments

No comments yet.