Talentd
FleetCode
Make and follow sheets.Sign in

Length of Longest Subarray With at Most K Frequency solution and explanation

MediumArrayHash TableSliding Window6 min read60.4% acceptanceUpdated 9 Apr 2026
Length of Longest Subarray With at Most K Frequency | 2 Ways | Leetcode 2958 | codestorywithMIKcodestorywithMIK · 21:52 · 13K viewsWatch on YouTube
9 more videos on this problem
  1. Length of Longest Subarray With at Most K Frequency | 2 Ways | Leetcode 2958 | codestorywithMIKcodestorywithMIK · 21:52 · 13K views
  2. Length of Longest Subarray With at Most K Frequency - Leetcode 2958 - PythonNeetCodeIO · 8:02 · 12K views
  3. 2958. Length of Longest Subarray With at Most K Frequency | 2 Pointers | Sliding WindowAryan Mittal · 10:25 · 4K views
  4. 2958. Length of Longest Subarray With at Most K Frequency | leetcode daily challenge | DSA | ShashShashCode · 14:56 · 2K views
  5. 2958. Length of Longest Subarray With at Most K Frequency | LEETCODE BIWEEKLY 119 | 2 POINTERScode Explainer · 10:01 · 752 views
  6. 2958. Length of Longest Subarray With at Most K Frequency - Problem Solving بالعربيAhmed Elemam - أحمد الإمام · 38:09 · 726 views
  7. 2958. Length of Longest Subarray With at Most K Frequency (Leetcode Medium)Programming Live with Larry · 6:19 · 395 views
  8. LeetCode Challenge: 2958. Length of Longest Subarray With at Most K Frequency | C++ | Sliding WindowSHWETA BHAGAT · 27:17 · 375 views
  9. Leetcode | 2958. Length of Longest Subarray With at Most K Frequency | Medium | Java SolutionDeveloper Docs · 9:43 · 296 views
  10. Length of Longest Subarray With at Most K Frequency - LeetCode 2958 - PythonAlpha-Code · 10:05 · 252 views

The problem

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.

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

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 overview

Problem Overview: Given an integer array nums and an integer k, find the length of the longest contiguous subarray where every number appears at most k times. The constraint applies to each distinct value inside the chosen window.

Approach 1: Sliding Window with Frequency Map (O(n) time, O(n) space)

This problem fits the classic sliding window pattern on arrays. Maintain two pointers left and right representing the current window and track element counts using a hash map. Expand the window by moving right and increment the frequency of nums[right]. If the frequency exceeds k, the window becomes invalid. Move left forward while decrementing counts until the constraint is restored.

At every step, the window represents a valid subarray where each value appears at most k times. Track the maximum window size using right - left + 1. Each element enters and leaves the window at most once, which keeps the total runtime linear. The frequency tracking uses a hash map from the hash table family, making updates and lookups constant time on average.

This approach works because the constraint is monotonic with respect to window expansion. Once a value appears more than k times, shrinking from the left is the only operation needed to restore validity. The algorithm scans the array once and dynamically maintains the best answer.

Approach 2: Binary Search Over Subarray Length (O(n log n) time, O(n) space)

Another way to view the problem is as a decision question: for a given length L, does any subarray of size L satisfy the frequency constraint? Because larger valid subarrays imply smaller ones are also valid, the answer space is monotonic. This allows binary search over the possible length range from 1 to n.

For each candidate length, scan the array using a fixed-size window and maintain a frequency map. When the window grows beyond L, decrement the frequency of the outgoing element. Track whether any window maintains all frequencies ≤ k. If a valid window exists, increase the search range; otherwise decrease it.

This method separates the validation logic from the optimization step, which can make reasoning easier in some scenarios. However, every binary search step performs a full linear scan, giving O(n log n) time complexity.

Recommended for interviews: The sliding window with a frequency map is the expected solution. It demonstrates understanding of window expansion, constraint maintenance, and hash-based counting in linear time. Binary search shows alternative thinking, but interviewers usually look for the O(n) sliding window implementation.

Approach 1: Sliding Window with Frequency Map

Use a sliding window technique to find the longest subarray that satisfies the condition where no element occurs more than k times. You can maintain a frequency map that tracks the count of each element in the current window.

def longest_good_subarray(nums, k):
    from collections import defaultdict
    freq = defaultdict(int)
    start = 0
    max_len = 0

    for end in range(len(nums)):
        freq[nums[end]] += 1
        while freq[nums[end]] > k:
            freq[nums[start]] -= 1
            if freq[nums[start]] == 0:
                del freq[nums[start]]
            start += 1
        max_len = max(max_len, end - start + 1)
    return max_len

# Example usage
nums = [1, 2, 3, 1, 2, 3, 1, 2]
k = 2
print(longest_good_subarray(nums, k))
import java.util.HashMap;
import java.util.Map;

public class LongestGoodSubarray {
    public static int longestGoodSubarray(int[] nums, int k) {
        Map<Integer, Integer> freq = new HashMap<>();
        int start = 0, max_len = 0;

        for (int end = 0; end < nums.length; end++) {
            freq.put(nums[end], freq.getOrDefault(nums[end], 0) + 1);
            while (freq.get(nums[end]) > k) {
                freq.put(nums[start], freq.get(nums[start]) - 1);
                if (freq.get(nums[start]) == 0) {
                    freq.remove(nums[start]);
                }
                start++;
            }
            max_len = Math.max(max_len, end - start + 1);
        }

        return max_len;
    }

    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 1, 2, 3, 1, 2};
        int k = 2;
        System.out.println(longestGoodSubarray(nums, k));
    }
}
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

int longestGoodSubarray(vector<int>& nums, int k) {
    unordered_map<int, int> freq;
    int start = 0, max_len = 0;

    for (int end = 0; end < nums.size(); ++end) {
        freq[nums[end]]++;
        while (freq[nums[end]] > k) {
            freq[nums[start]]--;
            if (freq[nums[start]] == 0) {
                freq.erase(nums[start]);
            }
            start++;
        }
        max_len = max(max_len, end - start + 1);
    }

    return max_len;
}

int main() {
    vector<int> nums = {1, 2, 3, 1, 2, 3, 1, 2};
    int k = 2;
    cout << longestGoodSubarray(nums, k) << endl;
    return 0;
}
function longestGoodSubarray(nums, k) {
    let freq = new Map();
    let start = 0, max_len = 0;

    for (let end = 0; end < nums.length; end++) {
        freq.set(nums[end], (freq.get(nums[end]) || 0) + 1);

        while (freq.get(nums[end]) > k) {
            freq.set(nums[start], freq.get(nums[start]) - 1);
            if (freq.get(nums[start]) === 0) {
                freq.delete(nums[start]);
            }
            start++;
        }

        max_len = Math.max(max_len, end - start + 1);
    }

    return max_len;
}

const nums = [1, 2, 3, 1, 2, 3, 1, 2];
const k = 2;
console.log(longestGoodSubarray(nums, k));
#include <stdio.h>
#include <stdlib.h>

int longestGoodSubarray(int* nums, int numsSize, int k) {
    int start = 0, max_len = 0;
    int* frequency = (int*)calloc(1000000001, sizeof(int));
    int distinct = 0;

    for (int end = 0; end < numsSize; end++) {
        frequency[nums[end]]++;
        if (frequency[nums[end]] == 1) {
            distinct++;
        }

        while (frequency[nums[end]] > k) {
            frequency[nums[start]]--;
            if (frequency[nums[start]] == 0) {
                distinct--;
            }
            start++;
        }

        if (frequency[nums[end]] <= k) {
            max_len = (end - start + 1) > max_len ? (end - start + 1) : max_len;
        }
    }

    free(frequency);
    return max_len;
}

int main() {
    int nums[] = {1, 2, 3, 1, 2, 3, 1, 2};
    int k = 2;
    int length = longestGoodSubarray(nums, 8, k);
    printf("%d\n", length);
    return 0;
}
using System;
using System.Collections.Generic;

class Program {
    public static int LongestGoodSubarray(int[] nums, int k) {
        Dictionary<int, int> freq = new Dictionary<int, int>();
        int start = 0, max_len = 0;

        for (int end = 0; end < nums.Length; end++) {
            if (freq.ContainsKey(nums[end]))
                freq[nums[end]]++;
            else
                freq[nums[end]] = 1;

            while (freq[nums[end]] > k) {
                freq[nums[start]]--;
                if (freq[nums[start]] == 0)
                    freq.Remove(nums[start]);
                start++;
            }

            max_len = Math.Max(max_len, end - start + 1);
        }

        return max_len;
    }

    static void Main() {
        int[] nums = {1, 2, 3, 1, 2, 3, 1, 2};
        int k = 2;
        Console.WriteLine(LongestGoodSubarray(nums, k));
    }
}

Using a Python defaultdict to manage element frequencies, this implementation applies the sliding window technique similarly. The start and end pointers are adjusted accordingly, and the maximum valid subarray length is recorded.

Complexity

Time Complexity: O(n).
Space Complexity: O(n) due to the storage requirements of the frequency dictionary.

Try this approach in the editor

Approach 2: Binary Search Over Subarray Length

A different approach is to use binary search to determine the maximum subarray length. The problem translates to searching for the maximum length for which a good subarray exists, using a helper function that verifies subarray validity in O(n) time.

def is_good_subarray(nums, subarray_size, k):
    from collections import defaultdict
    freq = defaultdict(int)
    for i in range(subarray_size):
        freq[nums[i]] += 1
        if freq[nums[i]] > k:
            return False
    for i in range(subarray_size, len(nums)):
        freq[nums[i]] += 1
        if freq[nums[i]] > k:
            return False
        freq[nums[i - subarray_size]] -= 1
        if freq[nums[i - subarray_size]] == 0:
            del freq[nums[i - subarray_size]]
    return True

def longest_good_subarray(nums, k):
    low, high, answer = 1, len(nums), 0
    while low <= high:
        mid = low + (high - low) // 2
        if is_good_subarray(nums, mid, k):
            answer = mid
            low = mid + 1
        else:
            high = mid - 1
    return answer

nums = [1, 2, 3, 1, 2, 3, 1, 2]
k = 2
print(longest_good_subarray(nums, k))
import java.util.HashMap;
import java.util.Map;

public class LongestGoodSubarrayBinarySearch {
    public static boolean isGoodSubarray(int[] nums, int subarraySize, int k) {
        Map<Integer, Integer> freq = new HashMap<>();
        for (int i = 0; i < subarraySize; i++) {
            freq.put(nums[i], freq.getOrDefault(nums[i], 0) + 1);
            if (freq.get(nums[i]) > k) return false;
        }
        for (int i = subarraySize; i < nums.length; i++) {
            freq.put(nums[i], freq.getOrDefault(nums[i], 0) + 1);
            if (freq.get(nums[i]) > k) return false;
            freq.put(nums[i - subarraySize], freq.get(nums[i - subarraySize]) - 1);
            if (freq.get(nums[i - subarraySize]) == 0) {
                freq.remove(nums[i - subarraySize]);
            }
        }
        return true;
    }

    public static int longestGoodSubarray(int[] nums, int k) {
        int low = 1, high = nums.length, answer = 0;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (isGoodSubarray(nums, mid, k)) {
                answer = mid;
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return answer;
    }

    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 1, 2, 3, 1, 2};
        int k = 2;
        System.out.println(longestGoodSubarray(nums, k));
    }
}
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

bool isGoodSubarray(vector<int>& nums, int subarraySize, int k) {
    unordered_map<int, int> freq;
    for (int i = 0; i < subarraySize; i++) {
        freq[nums[i]]++;
        if (freq[nums[i]] > k) return false;
    }
    for (int i = subarraySize; i < nums.size(); i++) {
        freq[nums[i]]++;
        if (freq[nums[i]] > k) return false;
        freq[nums[i - subarraySize]]--;
        if (freq[nums[i - subarraySize]] == 0) {
            freq.erase(nums[i - subarraySize]);
        }
    }
    return true;
}

int longestGoodSubarray(vector<int>& nums, int k) {
    int low = 1, high = nums.size(), answer = 0;

    while (low <= high) {
        int mid = low + (high - low) / 2;
        if (isGoodSubarray(nums, mid, k)) {
            answer = mid;
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }

    return answer;
}

int main() {
    vector<int> nums = {1, 2, 3, 1, 2, 3, 1, 2};
    int k = 2;
    cout << longestGoodSubarray(nums, k) << endl;
    return 0;
}
function isGoodSubarray(nums, subarraySize, k) {
    let freq = new Map();
    for (let i = 0; i < subarraySize; i++) {
        freq.set(nums[i], (freq.get(nums[i]) || 0) + 1);
        if (freq.get(nums[i]) > k) return false;
    }
    for (let i = subarraySize; i < nums.length; i++) {
        freq.set(nums[i], (freq.get(nums[i]) || 0) + 1);
        if (freq.get(nums[i]) > k) return false;
        freq.set(nums[i - subarraySize], freq.get(nums[i - subarraySize]) - 1);
        if (freq.get(nums[i - subarraySize]) === 0) {
            freq.delete(nums[i - subarraySize]);
        }
    }
    return true;
}

function longestGoodSubarray(nums, k) {
    let low = 1, high = nums.length, answer = 0;
    while (low <= high) {
        let mid = Math.floor(low + (high - low) / 2);
        if (isGoodSubarray(nums, mid, k)) {
            answer = mid;
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    return answer;
}

const nums = [1, 2, 3, 1, 2, 3, 1, 2];
const k = 2;
console.log(longestGoodSubarray(nums, k));
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

bool isGoodSubarray(int* nums, int numsSize, int subarraySize, int k) {
    int* frequency = (int*)calloc(1000000001, sizeof(int));
    int distinct = 0;

    for (int i = 0; i < subarraySize; i++) {
        frequency[nums[i]]++;
    }

    for (int i = 0; i < numsSize; i++) {
        if (i >= subarraySize) {
            frequency[nums[i - subarraySize]]--;
        }
        if (frequency[nums[i]] > k) {
            free(frequency);
            return false;
        }
    }

    free(frequency);
    return true;
}

int longestGoodSubarray(int* nums, int numsSize, int k) {
    int low = 1, high = numsSize, answer = 0;

    while (low <= high) {
        int mid = low + (high - low) / 2;
        if (isGoodSubarray(nums, numsSize, mid, k)) {
            answer = mid;
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    return answer;
}

int main() {
    int nums[] = {1, 2, 3, 1, 2, 3, 1, 2};
    int k = 2;
    printf("%d\n", longestGoodSubarray(nums, 8, k));
    return 0;
}
using System;
using System.Collections.Generic;

class Program {
    public static bool IsGoodSubarray(int[] nums, int subarraySize, int k) {
        Dictionary<int, int> freq = new Dictionary<int, int>();
        for (int i = 0; i < subarraySize; i++) {
            if (!freq.ContainsKey(nums[i])) freq[nums[i]] = 0;
            freq[nums[i]]++;
            if (freq[nums[i]] > k) return false;
        }
        for (int i = subarraySize; i < nums.Length; i++) {
            if (!freq.ContainsKey(nums[i])) freq[nums[i]] = 0;
            freq[nums[i]]++;
            if (freq[nums[i]] > k) return false;
            freq[nums[i - subarraySize]]--;
            if (freq[nums[i - subarraySize]] == 0) freq.Remove(nums[i - subarraySize]);
        }
        return true;
    }

    public static int LongestGoodSubarray(int[] nums, int k) {
        int low = 1, high = nums.Length, answer = 0;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (IsGoodSubarray(nums, mid, k)) {
                answer = mid;
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return answer;
    }

    static void Main() {
        int[] nums = {1, 2, 3, 1, 2, 3, 1, 2};
        int k = 2;
        Console.WriteLine(LongestGoodSubarray(nums, k));
    }
}

In Python, the function employs binary search to explore the potential maximum subarray length. For each candidate length, the validity of the subarray is determined by a helper function that reviews the current sliding window setup using defaultdict for frequencies.

Complexity

Time Complexity: O(n log n).
Space Complexity: O(n) employing a dictionary for frequency counts.

Try this approach in the editor

Approach 3: Two Pointers

We can use two pointers j and i to represent the left and right endpoints of the subarray, initially both pointers point to the first element of the array.

Next, we iterate over each element x in the array nums. For each element x, we increment the occurrence count of x, then check if the current subarray meets the requirements. If the current subarray does not meet the requirements, we move the pointer j one step to the right, and decrement the occurrence count of nums[j], until the current subarray meets the requirements. Then we update the answer ans = max(ans, i - j + 1). Continue the iteration until i reaches the end of the array.

The time complexity is O(n), and the space complexity is O(n). Here, n is the length of the array nums.

function maxSubarrayLength(nums: number[], k: number): number {
    const cnt: Map<number, number> = new Map();
    let ans = 0;
    for (let i = 0, j = 0; i < nums.length; ++i) {
        cnt.set(nums[i], (cnt.get(nums[i]) ?? 0) + 1);
        for (; cnt.get(nums[i])! > k; ++j) {
            cnt.set(nums[j], cnt.get(nums[j])! - 1);
        }
        ans = Math.max(ans, i - j + 1);
    }
    return ans;
}
func maxSubarrayLength(nums []int, k int) (ans int) {
	cnt := map[int]int{}
	for i, j, n := 0, 0, len(nums); i < n; i++ {
		cnt[nums[i]]++
		for ; cnt[nums[i]] > k; j++ {
			cnt[nums[j]]--
		}
		ans = max(ans, i-j+1)
	}
	return
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Sliding Window with Frequency Map

Time Complexity: O(n).
Space Complexity: O(n) due to the storage requirements of the frequency dictionary.

Binary Search Over Subarray Length

Time Complexity: O(n log n).
Space Complexity: O(n) employing a dictionary for frequency counts.

Two Pointers–

Complexity analysis

ApproachTimeSpaceWhen to Use
Sliding Window with Frequency MapO(n)O(n)Best general solution for arrays where element frequency must stay within a limit
Binary Search Over Subarray LengthO(n log n)O(n)Useful when the answer space is monotonic and you want a clear separation between validation and search

Frequently asked questions

Is Length of Longest Subarray With at Most K Frequency easy or hard?

The problem is classified as Medium difficulty. The challenge is recognizing that the constraint can be maintained with a sliding window and frequency map. Once the pattern is identified, the implementation is straightforward and linear time.

Length of Longest Subarray With at Most K Frequency Python/Java solution

Python solutions typically use a dictionary or collections.Counter for frequency tracking, while Java implementations use HashMap<Integer, Integer>. Both implementations follow the same sliding window pattern with two pointers and run in O(n) time.

How to solve Length of Longest Subarray With at Most K Frequency in O(n)?

Use a sliding window and maintain a hash map that stores the frequency of elements in the current window. Expand the right pointer and update the frequency. If any element appears more than k times, move the left pointer and decrement counts until the window becomes valid. Track the maximum window length during the process.

What is the best approach for Length of Longest Subarray With at Most K Frequency?

The optimal approach uses a sliding window with a frequency hash map. Two pointers track the current window while a map stores how many times each value appears. When any frequency exceeds k, move the left pointer forward until the window becomes valid again. This solution runs in O(n) time with O(n) space.

Is Length of Longest Subarray With at Most K Frequency asked at Google/Amazon/Meta?

Problems involving sliding window frequency constraints frequently appear in interviews at companies like Amazon, Google, and Meta. Variants include longest substring with limited repeats or subarrays with frequency constraints. Interviewers use them to test window management and hash map usage.

What data structure is used in Length of Longest Subarray With at Most K Frequency?

The core data structure is a hash table (or dictionary) that stores the frequency of each element in the current window. Combined with two pointers for the sliding window, it allows constant‑time updates and checks while scanning the array.

What is the time complexity of Length of Longest Subarray With at Most K Frequency?

The optimal sliding window solution runs in O(n) time because each element enters and leaves the window at most once. Frequency updates and lookups in the hash map are O(1) on average. The auxiliary space is O(n) in the worst case if all elements are distinct.

Comments

Now write it yourselfClose this page and solve Length of Longest Subarray With at Most K Frequency in the editor, without looking.
Practise Length of Longest Subarray With at Most K Frequency