Longest subarray with absolute difference between any pair at most X
Last Updated :
22 Sep, 2025
Given an integer array arr[] and an integer x, Find the longest sub-array where the absolute difference between any two elements is not greater than x.
Examples:
Input: arr[] = [8, 4, 5, 6, 7], x = 3
Output: [4, 5, 6, 7]
Explanation: The longest valid subarray is [4, 5, 6, 7] because max = 7, min = 4 → difference = 3 which is less than equal to x.
Input: arr[] = [1, 10, 12, 13, 14], x = 2
Output: [12, 13, 14]
Explanation: The longest valid subarray is [12, 13, 14] because max = 14, min = 12 → difference = 2 which is less than equal to x.
[Naive Approach] Checking all subarrays - O(n3) Time and O(1) Space
The idea is to consider all subarrays one by one, find the maximum and minimum element of that sub-array and check if their difference is not greater than x. Among all such sub-arrays print the longest sub-array.
C++
#include <iostream>
#include<vector>
#include<climits>
using namespace std;
vector<int> longestSubarray(vector<int>& arr, int x) {
int n = arr.size();
int start = 0, maxLen = 1;
for (int i=0; i<n; i++) {
for (int j=i; j<n; j++) {
// Find minimum and maximum elements
int mini = INT_MAX, maxi = INT_MIN;
for (int k=i; k<=j; k++) {
mini = min(mini, arr[k]);
maxi = max(maxi, arr[k]);
}
// If difference is less than x,
// compare length of subarray
if (maxi - mini <= x && maxLen < j-i+1) {
maxLen = j-i+1;
start = i;
}
}
}
vector<int> res;
for (int i = start; i < start+maxLen; i++) {
res.push_back(arr[i]);
}
return res;
}
int main() {
vector<int> arr = { 8, 4, 5, 6, 7 };
int x = 3;
vector<int> res = longestSubarray(arr, x);
for (auto val: res) {
cout << val << " ";
}
cout << endl;
return 0;
}
Java
import java.util.ArrayList;
class GfG {
static ArrayList<Integer> longestSubarray(int[] arr, int x) {
int n = arr.length;
int start = 0, maxLen = 1;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// Find minimum and maximum elements
int mini = Integer.MAX_VALUE, maxi = Integer.MIN_VALUE;
for (int k = i; k <= j; k++) {
mini = Math.min(mini, arr[k]);
maxi = Math.max(maxi, arr[k]);
}
// If difference is less than x,
// compare length of subarray
if (maxi - mini <= x && maxLen < j - i + 1) {
maxLen = j - i + 1;
start = i;
}
}
}
ArrayList<Integer> res = new ArrayList<>();
for (int i = start; i < start + maxLen; i++) {
res.add(arr[i]);
}
return res;
}
public static void main(String[] args) {
int[] arr = {8, 4, 5, 6, 7 };
int x = 3;
ArrayList<Integer> res = longestSubarray(arr, x);
for (int val : res) {
System.out.print(val + " ");
}
System.out.println();
}
}
Python
def longestSubarray(arr, x):
n = len(arr)
start = 0
maxLen = 1
for i in range(n):
for j in range(i, n):
# Find minimum and maximum elements
mini = float('inf')
maxi = float('-inf')
for k in range(i, j + 1):
mini = min(mini, arr[k])
maxi = max(maxi, arr[k])
# If difference is less than x,
# compare length of subarray
if maxi - mini <= x and maxLen < j - i + 1:
maxLen = j - i + 1
start = i
return arr[start: start + maxLen]
if __name__ == "__main__":
arr = [8, 4, 5, 6, 7]
x = 3
res = longestSubarray(arr, x)
print(*res)
C#
using System;
using System.Collections.Generic;
class GfG {
static List<int> longestSubarray(int[] arr, int x) {
int n = arr.Length;
int start = 0, maxLen = 1;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// Find minimum and maximum elements
int mini = int.MaxValue, maxi = int.MinValue;
for (int k = i; k <= j; k++) {
mini = Math.Min(mini, arr[k]);
maxi = Math.Max(maxi, arr[k]);
}
// If difference is less than x,
// compare length of subarray
if (maxi - mini <= x && maxLen < j - i + 1) {
maxLen = j - i + 1;
start = i;
}
}
}
List<int> res = new List<int>();
for (int i = start; i < start + maxLen; i++) {
res.Add(arr[i]);
}
return res;
}
static void Main() {
int[] arr = {8, 4, 5, 6, 7};
int x = 3;
List<int> res = longestSubarray(arr, x);
Console.WriteLine(string.Join(" ", res));
}
}
JavaScript
function longestSubarray(arr, x) {
let n = arr.length;
let start = 0, maxLen = 1;
for (let i = 0; i < n; i++) {
for (let j = i; j < n; j++) {
// Find minimum and maximum elements
let mini = Infinity, maxi = -Infinity;
for (let k = i; k <= j; k++) {
mini = Math.min(mini, arr[k]);
maxi = Math.max(maxi, arr[k]);
}
// If difference is less than x,
// compare length of subarray
if (maxi - mini <= x && maxLen < j - i + 1) {
maxLen = j - i + 1;
start = i;
}
}
}
return arr.slice(start, start + maxLen);
}
// Driver Code
let arr = [8, 4, 5, 6, 7];
let x = 3;
let res = longestSubarray(arr, x);
console.log(res.join(" "));
[Better Approach] Using Sliding Window and Sorted Map - O(n * log n) Time and O(n) Space
We use a sliding window with an ordered map to maintain the minimum and maximum values in the current subarray. The window expands until the absolute difference exceeds x; if it does, we shrink the window from the left until the condition is satisfied again.
Working:
- Maintain two pointers start and end for the window.
- Insert elements into the map to track min and max.
- If (max - min) <= x, update the best subarray length.
- If (max - min) > x, move start forward and remove elements until valid.
- Finally, return the longest valid subarray found.
In C# and JavaScript, a custom structure is needed for min/max since they don’t have a built-in ordered map.
C++
#include <iostream>
#include <vector>
#include <map>
using namespace std;
vector<int> longestSubarray(vector<int>& arr, int x) {
int n = arr.size();
int maxLen = 0;
int beginning = 0;
map<int, int> window;
// Initialize the window
int start = 0, end = 0;
for (; end < n; end++) {
// Increment the count of that element in the window
window[arr[end]]++;
// maximum and minimum element in current window
auto minimum = window.begin()->first;
auto maximum = window.rbegin()->first;
// If the difference is not greater than X
if (maximum - minimum <= x) {
// Update the length of the longest subarray and
// store the beginning of the sub-array
if (maxLen < end - start + 1) {
maxLen = end - start + 1;
beginning = start;
}
}
// Decrease the size of the window
else {
while (start < end) {
// Remove the element at start
window[arr[start]]--;
// Remove the element from the window
// if its count is zero
if (window[arr[start]] == 0) {
window.erase(window.find(arr[start]));
}
// Increment the start of the window
start++;
// maximum and minimum element in the
// current window
auto minimum = window.begin()->first;
auto maximum = window.rbegin()->first;
// Stop decreasing the size of window
// when difference is not greater
if (maximum - minimum <= x)
break;
}
}
}
// Return the longest sub-array
vector<int> res;
for (int i = beginning; i < beginning + maxLen; i++)
res.push_back(arr[i]);
return res;
}
int main() {
vector<int> arr = {8, 4, 5, 6, 7 };
int x = 3;
vector<int> res = longestSubarray(arr, x);
for (auto val: res) {
cout << val << " ";
}
cout << endl;
return 0;
}
Java
import java.util.ArrayList;
import java.util.TreeMap;
class GfG {
static ArrayList<Integer> longestSubarray(int[] arr, int x) {
int n = arr.length;
int maxLen = 0;
int beginning = 0;
// map to store the maximum and the minimum elements for
// a given window
TreeMap<Integer, Integer> window = new TreeMap<>();
int start = 0, end = 0;
for (; end < n; end++) {
// Increment the count of that element in the window
window.put(arr[end], window.getOrDefault(arr[end], 0) + 1);
// maximum and minimum element in current window
int minimum = window.firstKey();
int maximum = window.lastKey();
// If the difference is not greater than X
if (maximum - minimum <= x) {
// Update the length of the longest subarray and
// store the beginning of the sub-array
if (maxLen < end - start + 1) {
maxLen = end - start + 1;
beginning = start;
}
}
// Decrease the size of the window
else {
while (start < end) {
// Remove the element at start
window.put(arr[start], window.get(arr[start]) - 1);
// Remove the element from the window
// if its count is zero
if (window.get(arr[start]) == 0) {
window.remove(arr[start]);
}
// Increment the start of the window
start++;
// maximum and minimum element in the
// current window
minimum = window.firstKey();
maximum = window.lastKey();
// Stop decreasing the size of window
// when difference is not greater
if (maximum - minimum <= x)
break;
}
}
}
// Return the longest sub-array
ArrayList<Integer> res = new ArrayList<>();
for (int i = beginning; i < beginning + maxLen; i++)
res.add(arr[i]);
return res;
}
public static void main(String[] args) {
int[] arr = {8, 4, 5, 6, 7};
int x = 3;
ArrayList<Integer> res = longestSubarray(arr, x);
for (int val : res) {
System.out.print(val + " ");
}
System.out.println();
}
}
Python
import bisect
def longestSubarray(arr, x):
n = len(arr)
window = []
max_len = 0
start = 0
beginning = 0
for end in range(n):
# insert arr[end] in sorted order
bisect.insort(window, arr[end])
# shrink window if max - min > x
while window[-1] - window[0] > x:
# remove arr[start] from window
idx = bisect.bisect_left(window, arr[start])
window.pop(idx)
start += 1
# update longest subarray
if end - start + 1 > max_len:
max_len = end - start + 1
beginning = start
return arr[beginning:beginning + max_len]
if __name__ == "__main__":
arr = [8, 4, 5, 6, 7]
x = 3
res = longestSubarray(arr, x)
for i in range(0, len(res)):
print(res[i], end=" ")
C#
using System;
using System.Collections.Generic;
using System.Linq;
// Custom multiset with O(1) min/max tracking
class MultiSet {
private SortedDictionary<int, int> dict = new SortedDictionary<int, int>();
private int minVal = int.MaxValue;
private int maxVal = int.MinValue;
// Insert element into multiset
public void Add(int x) {
if (!dict.ContainsKey(x)) dict[x] = 0;
dict[x]++;
if (x < minVal) minVal = x;
if (x > maxVal) maxVal = x;
}
// Remove element from multiset
public void Remove(int x) {
if (!dict.ContainsKey(x)) return;
dict[x]--;
if (dict[x] == 0) dict.Remove(x);
// Update min/max if the removed element was min or max
if (x == minVal || x == maxVal) {
if (dict.Count == 0) {
minVal = int.MaxValue;
maxVal = int.MinValue;
} else {
minVal = GetFirstKey();
maxVal = GetLastKey();
}
}
}
// Get smallest key in dictionary
private int GetFirstKey() {
foreach (var kv in dict) return kv.Key;
return 0;
}
// Get largest key in dictionary
private int GetLastKey() {
using (var e = dict.GetEnumerator()) {
int last = 0;
while (e.MoveNext()) last = e.Current.Key;
return last;
}
}
public int Min() => minVal;
public int Max() => maxVal;
}
class GfG {
static List<int> longestSubarray(int[] arr, int x) {
int n = arr.Length;
int maxLen = 0, beginning = 0;
MultiSet window = new MultiSet();
int start = 0;
// Expand the window
for (int end = 0; end < n; end++) {
window.Add(arr[end]);
// Shrink while condition is violated
while (window.Max() - window.Min() > x) {
window.Remove(arr[start]);
start++;
}
// Update best window length
if (end - start + 1 > maxLen) {
maxLen = end - start + 1;
beginning = start;
}
}
// Build result subarray
List<int> res = new List<int>();
for (int i = beginning; i < beginning + maxLen; i++)
res.Add(arr[i]);
return res;
}
static void Main() {
int[] arr = { 8, 4, 5, 6, 7 };
int x = 3;
List<int> res = longestSubarray(arr, x);
Console.WriteLine(string.Join(" ", res));
}
}
JavaScript
class Heap {
constructor(compare) {
this.data = [];
this.compare = compare;
}
size() { return this.data.length; }
peek() { return this.data[0]; }
push(val) {
this.data.push(val);
this._siftUp(this.data.length - 1);
}
pop() {
if (this.size() === 0) return null;
const top = this.data[0];
const last = this.data.pop();
if (this.size() > 0) {
this.data[0] = last;
this._siftDown(0);
}
return top;
}
_siftUp(i) {
while (i > 0) {
const p = (i - 1) >> 1;
if (this.compare(this.data[i], this.data[p])) {
[this.data[i], this.data[p]] = [this.data[p], this.data[i]];
i = p;
} else break;
}
}
_siftDown(i) {
const n = this.size();
while (true) {
let l = i * 2 + 1, r = i * 2 + 2, best = i;
if (l < n && this.compare(this.data[l], this.data[best])) best = l;
if (r < n && this.compare(this.data[r], this.data[best])) best = r;
if (best !== i) {
[this.data[i], this.data[best]] = [this.data[best], this.data[i]];
i = best;
} else break;
}
}
}
function longestSubarray(arr, x) {
const n = arr.length;
let maxLen = 0, beginning = 0;
// frequency map
const freq = new Map();
// min-heap and max-heap
const minHeap = new Heap((a, b) => a < b);
const maxHeap = new Heap((a, b) => a > b);
let start = 0;
for (let end = 0; end < n; end++) {
freq.set(arr[end], (freq.get(arr[end]) || 0) + 1);
minHeap.push(arr[end]);
maxHeap.push(arr[end]);
// shrink window while invalid
while (true) {
while (minHeap.size() > 0 && (freq.get(minHeap.peek()) || 0) === 0)
minHeap.pop();
while (maxHeap.size() > 0 && (freq.get(maxHeap.peek()) || 0) === 0)
maxHeap.pop();
if (maxHeap.peek() - minHeap.peek() <= x) break;
freq.set(arr[start], freq.get(arr[start]) - 1);
start++;
}
// update longest window
if (end - start + 1 > maxLen) {
maxLen = end - start + 1;
beginning = start;
}
}
let res = [];
for (let i = beginning; i < beginning + maxLen; i++) res.push(arr[i]);
return res;
}
// Driver Code
let arr = [8, 4, 5, 6, 7];
let x = 3;
let res = longestSubarray(arr, x);
console.log(res.join(" "));
[Expected Approach] Using Dequeues - O(n) Time and O(n) Space
We will be using two deques to maintain the minimum and maximum of the current window in O(1). Expand the window while the difference ≤ x, and shrink it when the difference > x to find the longest valid subarray.
Working:
- Keep two deques:
-> minDeque → increasing order (front = minimum).
-> maxDeque → decreasing order (front = maximum). - Traverse array with end pointer:
-> Insert element in both deques while maintaining order. - If (maxDeque.front() - minDeque.front()) > x:
-> Move start pointer forward.
-> Remove elements from deques if they go out of the window. - Track the maximum window size where difference ≤ x.
C++
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
vector<int> longestSubarray(vector<int>& arr, int x) {
deque<int> minQueue, maxQueue;
int n = arr.size(), start = 0, end = 0;
// Pointers to mark the range of maximum subarray
int resStart = 0, resEnd = 0;
while (end < n) {
// Pop the elements greater than current element
// from min Queue
while (!minQueue.empty()
&& arr[minQueue.back()] > arr[end])
minQueue.pop_back();
// Pop the elements smaller than current element
// from max Queue
while (!maxQueue.empty()
&& arr[maxQueue.back()] < arr[end])
maxQueue.pop_back();
minQueue.push_back(end);
maxQueue.push_back(end);
// Check if the subarray has maximum difference less
// than x
while (arr[maxQueue.front()] - arr[minQueue.front()]
> x) {
// Reduce the length of sliding window by moving
// the start pointer
if (start == minQueue.front())
minQueue.pop_front();
if (start == maxQueue.front())
maxQueue.pop_front();
start += 1;
}
// Maximize the subarray length
if (end - start > resEnd - resStart) {
resStart = start;
resEnd = end;
}
end += 1;
}
vector<int> res;
for (int i = resStart; i <= resEnd; i++)
res.push_back(arr[i]);
return res;
}
int main() {
vector<int> arr = { 8, 4, 5, 6, 7 };
int x = 3;
vector<int> res = longestSubarray(arr, x);
for (auto val: res) {
cout << val << " ";
}
cout << endl;
return 0;
}
Java
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
class GfG {
static ArrayList<Integer> longestSubarray(int[] arr, int x) {
Deque<Integer> minQueue = new LinkedList<>();
Deque<Integer> maxQueue = new LinkedList<>();
int n = arr.length, start = 0, end = 0;
int resStart = 0, resEnd = 0;
while (end < n) {
// Pop the elements greater than current element
// from min Queue
while (!minQueue.isEmpty() && arr[minQueue.peekLast()] > arr[end])
minQueue.pollLast();
// Pop the elements smaller than current element
// from max Queue
while (!maxQueue.isEmpty() && arr[maxQueue.peekLast()] < arr[end])
maxQueue.pollLast();
// Push the current index to both the queues
minQueue.addLast(end);
maxQueue.addLast(end);
// Check if the subarray has maximum difference less
// than x
while (arr[maxQueue.peekFirst()] - arr[minQueue.peekFirst()] > x) {
// Reduce the length of sliding window by moving
// the start pointer
if (start == minQueue.peekFirst())
minQueue.pollFirst();
if (start == maxQueue.peekFirst())
maxQueue.pollFirst();
start += 1;
}
// Maximize the subarray length
if (end - start > resEnd - resStart) {
resStart = start;
resEnd = end;
}
end += 1;
}
ArrayList<Integer> res = new ArrayList<>();
for (int i = resStart; i <= resEnd; i++)
res.add(arr[i]);
return res;
}
public static void main(String[] args) {
int[] arr = { 8, 4, 5, 6, 7 };
int x = 3;
ArrayList<Integer> res = longestSubarray(arr, x);
for (int val : res) {
System.out.print(val + " ");
}
System.out.println();
}
}
Python
from collections import deque
def longestSubarray(arr, x):
minQueue = deque()
maxQueue = deque()
n = len(arr)
start = end = 0
resStart = resEnd = 0
while end < n:
# Pop the elements greater than current element
# from min Queue
while minQueue and arr[minQueue[-1]] > arr[end]:
minQueue.pop()
# Pop the elements smaller than current element
# from max Queue
while maxQueue and arr[maxQueue[-1]] < arr[end]:
maxQueue.pop()
# Push the current index to both the queues
minQueue.append(end)
maxQueue.append(end)
# Check if the subarray has maximum difference less
# than x
while arr[maxQueue[0]] - arr[minQueue[0]] > x:
# Reduce the length of sliding window by moving
# the start pointer
if start == minQueue[0]:
minQueue.popleft()
if start == maxQueue[0]:
maxQueue.popleft()
start += 1
# Maximize the subarray length
if end - start > resEnd - resStart:
resStart, resEnd = start, end
end += 1
return arr[resStart:resEnd+1]
if __name__ == "__main__":
arr = [8, 4, 5, 6, 7]
x = 3
res = longestSubarray(arr, x)
print(*res)
C#
using System;
using System.Collections.Generic;
class GfG {
static List<int> longestSubarray(int[] arr, int x) {
LinkedList<int> minQueue = new LinkedList<int>();
LinkedList<int> maxQueue = new LinkedList<int>();
int n = arr.Length, start = 0, end = 0;
int resStart = 0, resEnd = 0;
while (end < n) {
// Pop the elements greater than current element
// from min Queue
while (minQueue.Count > 0 && arr[minQueue.Last.Value] > arr[end])
minQueue.RemoveLast();
// Pop the elements smaller than current element
// from max Queue
while (maxQueue.Count > 0 && arr[maxQueue.Last.Value] < arr[end])
maxQueue.RemoveLast();
// Push the current index to both the queues
minQueue.AddLast(end);
maxQueue.AddLast(end);
// Check if the subarray has maximum difference less
// than x
while (arr[maxQueue.First.Value] - arr[minQueue.First.Value] > x) {
// Reduce the length of sliding window by moving
// the start pointer
if (start == minQueue.First.Value)
minQueue.RemoveFirst();
if (start == maxQueue.First.Value)
maxQueue.RemoveFirst();
start += 1;
}
// Maximize the subarray length
if (end - start > resEnd - resStart) {
resStart = start;
resEnd = end;
}
end += 1;
}
// Return the longest sub-array
List<int> res = new List<int>();
for (int i = resStart; i <= resEnd; i++)
res.Add(arr[i]);
return res;
}
static void Main() {
int[] arr = { 8, 4, 5, 6, 7 };
int x = 3;
List<int> res = longestSubarray(arr, x);
Console.WriteLine(string.Join(" ", res));
}
}
JavaScript
function longestSubarray(arr, x) {
let minQueue = [];
let maxQueue = [];
let start = 0, end = 0, resStart = 0, resEnd = 0;
while (end < arr.length) {
// Maintain minQueue: remove elements greater than current
while (minQueue.length && arr[minQueue[minQueue.length - 1]] > arr[end])
minQueue.pop();
// Maintain maxQueue: remove elements smaller than current
while (maxQueue.length && arr[maxQueue[maxQueue.length - 1]] < arr[end])
maxQueue.pop();
minQueue.push(end);
maxQueue.push(end);
// Shrink window if difference exceeds x
while (arr[maxQueue[0]] - arr[minQueue[0]] > x) {
if (start === minQueue[0]) minQueue.shift();
if (start === maxQueue[0]) maxQueue.shift();
start++;
}
// Update result if current window is longer
if (end - start > resEnd - resStart) {
resStart = start;
resEnd = end;
}
end++;
}
// Return the longest subarray satisfying the condition
return arr.slice(resStart, resEnd + 1);
}
// Driver Code
let arr = [8, 4, 5, 6, 7];
let x = 3;
const res = longestSubarray(arr, x);
console.log(res.join(" "));
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem