Given an array of positive integers, the task is to find the length of the longest subarray that contains at most two distinct integers.
A subarray must be contiguous. The goal is to maximize its length while ensuring that no more than two unique numbers exist inside it.
- 1 ≤ arr.size() ≤ 10^5
- 1 ≤ arr[i] ≤ 10^5
When I read this problem, I immediately noticed two important things:
- The subarray must be continuous.
- We are allowed at most two distinct integers.
Whenever I see a problem asking for the longest subarray under a restriction, I think about the Sliding Window technique.
Instead of checking every possible subarray, which would be very slow, I can maintain a window and adjust it dynamically.
If the number of distinct integers becomes more than two, I shrink the window from the left.
This way, I can solve the problem efficiently in linear time.
-
Use two pointers: left and right.
-
Maintain a frequency map to store counts of elements inside the window.
-
Expand the right pointer one step at a time.
-
Add the current element to the frequency map.
-
If the number of distinct elements becomes greater than 2:
- Move the left pointer forward.
- Reduce frequency of elements.
- Remove elements whose frequency becomes zero.
-
After adjusting the window, update the maximum length.
-
Continue until the right pointer reaches the end of the array.
-
HashMap / unordered_map / Map / Dictionary
- Used to store element frequencies.
-
Two pointers (left and right)
- Used to manage the sliding window.
- Each element is added to the window once.
- Each element is removed from the window at most once.
- The window dynamically adjusts to maintain at most two distinct integers.
- Maximum length is updated during each valid window expansion.
Time Complexity: O(n)
- Each element is visited at most twice.
- n is the size of the array.
Space Complexity: O(1)
- The frequency map stores at most 3 elements temporarily.
- Since this number is constant, space complexity is constant.
class Solution {
public:
int totalElements(vector<int> &arr) {
unordered_map<int, int> freq;
int left = 0;
int maxLen = 0;
for (int right = 0; right < arr.size(); right++) {
freq[arr[right]]++;
while (freq.size() > 2) {
freq[arr[left]]--;
if (freq[arr[left]] == 0) {
freq.erase(arr[left]);
}
left++;
}
maxLen = max(maxLen, right - left + 1);
}
return maxLen;
}
};import java.util.*;
class Solution {
public int totalElements(int[] arr) {
HashMap<Integer, Integer> freq = new HashMap<>();
int left = 0;
int maxLen = 0;
for (int right = 0; right < arr.length; right++) {
freq.put(arr[right], freq.getOrDefault(arr[right], 0) + 1);
while (freq.size() > 2) {
freq.put(arr[left], freq.get(arr[left]) - 1);
if (freq.get(arr[left]) == 0) {
freq.remove(arr[left]);
}
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
}class Solution {
totalElements(arr) {
let freq = new Map();
let left = 0;
let maxLen = 0;
for (let right = 0; right < arr.length; right++) {
freq.set(arr[right], (freq.get(arr[right]) || 0) + 1);
while (freq.size > 2) {
freq.set(arr[left], freq.get(arr[left]) - 1);
if (freq.get(arr[left]) === 0) {
freq.delete(arr[left]);
}
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
}class Solution:
def totalElements(self, arr):
freq = {}
left = 0
maxLen = 0
for right in range(len(arr)):
freq[arr[right]] = freq.get(arr[right], 0) + 1
while len(freq) > 2:
freq[arr[left]] -= 1
if freq[arr[left]] == 0:
del freq[arr[left]]
left += 1
maxLen = max(maxLen, right - left + 1)
return maxLen-
Initialize a frequency map to store element counts.
-
Set left pointer to 0.
-
Start iterating with right pointer from 0 to n-1.
-
Add arr[right] to the map.
-
If map size becomes greater than 2:
- Reduce frequency of arr[left].
- Remove it if frequency becomes zero.
- Move left pointer forward.
-
Calculate current window length as right - left + 1.
-
Update maximum length.
-
Continue until the loop ends.
This logic remains identical across all languages. Only syntax changes.
Input: arr = [2, 1, 2] Output: 3
Input: arr = [3, 1, 2, 2, 2, 2] Output: 5
C++:
- Compile using g++ filename.cpp
- Run using ./a.out
Java:
- Compile using javac Solution.java
- Run using java Solution
JavaScript:
- Run using node filename.js
Python3:
- Run using python filename.py
- Brute force approach would take O(n^2).
- Sliding window reduces it to O(n).
- This pattern works for similar problems like longest substring with K distinct characters.
- Always shrink the window only when constraint breaks.