Difficulty | Source | Tags | ||||
---|---|---|---|---|---|---|
Medium |
160 Days of Problem Solving |
|
The problem can be found at the following link: Question Link
Given an array of positive integers arr[]
and a non-negative integer x
, the task is to find the longest sub-array where the absolute difference between any two elements is not greater than x
.
If multiple such subarrays exist, return the one that starts at the smallest index.
arr[] = [8, 4, 2, 6, 7]
x = 4
[4, 2, 6]
- The sub-array [4, 2, 6] has no pair of elements with absolute difference greater than 4.
- Other subarrays either don't meet the condition or are shorter.
arr[] = [15, 10, 1, 2, 4, 7, 2]
x = 5
[2, 4, 7, 2]
- The sub-array described by indexes [3..6], i.e. [2, 4, 7, 2] contains no such difference of two elements which is greater than 5.
This approach uses two deques to dynamically maintain the minimum and maximum elements within the sliding window.
- minQ tracks the minimum values in the current window.
- maxQ tracks the maximum values in the current window.
- If
maxQ.front() - minQ.front()
exceedsx
, we shrink the window from the left. - At every step, we check if the current window length is the longest valid window seen so far.
- Initialize
start
pointer and two deques:minQ
(for minimum) andmaxQ
(for maximum). - Expand the window by adding the current element to both deques.
- If the difference between max and min exceeds
x
, shrink the window by incrementingstart
. - Track the longest valid window and its starting position.
- Return the subarray corresponding to the longest valid window.
Complexity | Analysis |
---|---|
Time Complexity | O(N) - Each element is pushed and popped from the deque at most once. |
Space Complexity | O(N) - In the worst case, both deques can hold all indices. |
class Solution {
public:
vector<int> longestSubarray(vector<int>& arr, int x) {
deque<int> minQ, maxQ;
int n = arr.size(), start = 0, resStart = 0, resEnd = 0;
for (int end = 0; end < n; end++) {
while (!minQ.empty() && arr[minQ.back()] > arr[end]) minQ.pop_back();
while (!maxQ.empty() && arr[maxQ.back()] < arr[end]) maxQ.pop_back();
minQ.push_back(end), maxQ.push_back(end);
while (arr[maxQ.front()] - arr[minQ.front()] > x) {
if (minQ.front() == start) minQ.pop_front();
if (maxQ.front() == start) maxQ.pop_front();
start++;
}
if (end - start > resEnd - resStart) resStart = start, resEnd = end;
}
return vector<int>(arr.begin() + resStart, arr.begin() + resEnd + 1);
}
};
⚡ Alternative Approaches
2️⃣ Using Ordered Set (O(N log N) Time, O(N) Space)
Key Idea
- Use a
multiset
to dynamically maintain the window elements. - Get the min and max in constant time using
*begin()
and*rbegin()
. - Shrink the window if the max-min difference exceeds
x
.
class Solution {
public:
vector<int> longestSubarray(vector<int>& arr, int x) {
multiset<int> window;
int start = 0, resStart = 0, resLen = 0;
for (int end = 0; end < arr.size(); end++) {
window.insert(arr[end]);
while (*window.rbegin() - *window.begin() > x) window.erase(window.find(arr[start++]));
if (end - start + 1 > resLen) resStart = start, resLen = end - start + 1;
}
return vector<int>(arr.begin() + resStart, arr.begin() + resStart + resLen);
}
};
3️⃣ Brute Force (O(N²) Time, O(1) Space)
Key Idea
- For every subarray
arr[i..j]
, check the max and min values and verify the condition. - This is only feasible for small arrays.
class Solution {
public:
vector<int> longestSubarray(vector<int>& arr, int x) {
int n = arr.size(), maxLen = 0, resStart = 0;
for (int i = 0; i < n; i++) {
int minVal = arr[i], maxVal = arr[i];
for (int j = i; j < n; j++) {
minVal = min(minVal, arr[j]), maxVal = max(maxVal, arr[j]);
if (maxVal - minVal > x) break;
if (j - i + 1 > maxLen) resStart = i, maxLen = j - i + 1;
}
}
return vector<int>(arr.begin() + resStart, arr.begin() + resStart + maxLen);
}
};
📊 Comparison of Approaches
Approach | ⏱️ Time Complexity | 🗂️ Space Complexity | ✅ Pros | |
---|---|---|---|---|
Sliding Window + Deque (Optimal) | 🟢 O(N) | 🟢 O(N) | Fastest for all cases | Slightly complex |
Ordered Set (Multiset) | 🟡 O(N log N) | 🟡 O(N) | Elegant window handling | Slower than deque |
Brute Force | 🔴 O(N²) | 🟢 O(1) | Simple to implement | Very slow for large arrays |
💡 Best Choice?
- ✅ For optimal performance: Sliding Window + Monotonic Deque (O(N) time, O(N) space).
- ✅ For simpler code: Ordered Set is easier than deques.
- ✅ For small inputs: Brute Force is acceptable for
.
class Solution {
public ArrayList<Integer> longestSubarray(int[] arr, int x) {
Deque<Integer> minQ = new ArrayDeque<>(), maxQ = new ArrayDeque<>();
int n = arr.length, start = 0, resStart = 0, resLen = 0;
for (int end = 0; end < n; end++) {
while (!minQ.isEmpty() && arr[minQ.peekLast()] > arr[end]) minQ.pollLast();
while (!maxQ.isEmpty() && arr[maxQ.peekLast()] < arr[end]) maxQ.pollLast();
minQ.addLast(end);
maxQ.addLast(end);
while (arr[maxQ.peekFirst()] - arr[minQ.peekFirst()] > x) {
if (minQ.peekFirst() == start) minQ.pollFirst();
if (maxQ.peekFirst() == start) maxQ.pollFirst();
start++;
}
if (end - start + 1 > resLen) {
resStart = start;
resLen = end - start + 1;
}
}
ArrayList<Integer> res = new ArrayList<>();
for (int i = resStart; i < resStart + resLen; i++) res.add(arr[i]);
return res;
}
}
from collections import deque
class Solution:
def longestSubarray(self, arr, x):
minQ, maxQ, start, resStart, resEnd = deque(), deque(), 0, 0, 0
for end in range(len(arr)):
while minQ and arr[minQ[-1]] > arr[end]: minQ.pop()
while maxQ and arr[maxQ[-1]] < arr[end]: maxQ.pop()
minQ.append(end), maxQ.append(end)
while arr[maxQ[0]] - arr[minQ[0]] > x:
if minQ[0] == start: minQ.popleft()
if maxQ[0] == start: maxQ.popleft()
start += 1
if end - start > resEnd - resStart: resStart, resEnd = start, end
return arr[resStart:resEnd + 1]
For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: Any Questions. Let’s make this learning journey more collaborative!
⭐ If you find this helpful, please give this repository a star! ⭐