'Find the Longest Subarray

Given an array of integers, what is the length of the longest subarray containing no more than two distinct values such that the distinct values differ by no more than 1?

Example:

arr = [0,1,2,1,2,3]

The largest such subarray has length 4: [1,2,1,2].

arr = [1, 1, 1, 3, 3, 2, 2]

The largest such subarray has length 4: [3, 3, 2, 2]. The values 1 and 3 differ by more than 1 so [1, 1, 1, 3, 3] is not valid.



Solution 1:[1]

Here's O(1) space, O(n) time. We can get the answer for the sequence ending at A[i] by looking at the best sequence ending at A[i-1] that possibly included higher elements, and the best sequence ending at A[i-1] that possibly included lower elements.

JavaScript code:

function f(A){
  if (A.length < 2)
    return A.length;
    
  let best = 1;
  let bestLower = 1;
  let bestHigher = 1;
  
  for (let i=1; i<A.length; i++){
    if (A[i] == A[i-1]){
      bestLower = bestLower + 1;
      bestHigher = bestHigher + 1;
    
    } else if (A[i] - 1 == A[i-1]){
      bestLower = 1 + bestHigher;
      bestHigher = 1;
    
    } else if (A[i] + 1 == A[i-1]){
      bestHigher = 1 + bestLower;
      bestLower = 1;
    
    } else {
      bestLower = 1;
      bestHigher = 1;
    }

    best = Math.max(best, bestLower, bestHigher);
  }
  
  return best;
}

arrays = [
  [0, 1, 2, 1, 2, 3], // length = 4; [1,2,1,2]
  [1, 2, 3, 4, 5], // length = 2; [1,2]
  [1, 1, 1, 3, 3, 2, 2] // length = 4; [3,3,2,2]
];

for (let arr of arrays){
  console.log(JSON.stringify(arr));
  console.log(f(arr));
}

Solution 2:[2]

With this code, we keep looking to the element before the current element, checking if their difference is not bigger than one, and if that element is inside the current range of the subarray we're counting. In the end, we need to increment our total, as we want the length of the array.

Python Code:

def longestSub(arr):
    size = len(arr)
    cMax = cMin = arr[0]
    total = current = 0

    cMax = cMin = arr[0]
    #We will use cMax and cMin to keep track of the range of our current subarray
    for i in range(1,size):
        if(abs(arr[i] - arr[i-1]) <= 1):
            if(arr[i] == cMax or arr[i] == cMin):
                current += 1
            else:
                if(current > total):
                    total = current
                current = 1
                cMax = max(arr[i-1],arr[i])
                cMin = min(arr[i-1],arr[i])
        else:
            if(current > total):
                total = current
            cMin = cMax = arr[i]
    return total+1

if __name__ == "__main__":
    arr = [0, 1, 2, 1, 2, 3]    #length = 4; [1,2,1,2]
    print(longestSub(arr))
    arr = [1, 2, 3, 4, 5]       #length = 2; [1,2]
    print(longestSub(arr))
    arr = [1, 1, 1, 3, 3, 2, 2] #length = 4; [3,3,2,2]
    print(longestSub(arr))

Solution 3:[3]

I don't think there is any solution better than O(n).

You didn't specify any language, so the pseudocode should look something like this (I ended up writing a python script):

a = [1, 1, 1, 3, 3, 2, 2]
max_solution_arr = []
cur_sol_arr = []
max_length = 0
cur_len = 0

def min_(a, a_i):
  if len(a) == 0:
      return a_i
  return min(a)

def max_(a, a_i):
  if len(a) == 0:
      return a_i
  return max(a)
for i, a_i in enumerate(a):
    if i == 0:
        cur_sol_arr.append(a_i)
        cur_len += 1
    else:
        if (abs(a[i] - min_(cur_sol_arr, a[i])) <= 1) and (abs(a[i] - max_(cur_sol_arr, a[i])) <= 1):
            # solution extend
            cur_sol_arr.append(a_i)
            cur_len += 1
        else:
            # we need to break, update solution
            if cur_len > max_length:
                max_length = cur_len
                max_solution_arr = cur_sol_arr[:] # make a copy here
                cur_sol_arr = [a_i] # delete
                cur_len = 1
# residual

if cur_len > max_length:
   max_length = cur_len
   max_solution_arr = cur_sol_arr # make a copy here

print(max_solution_arr)

The idea is you'll keep an array where you'll continue appending elements unless the condition is not met (> 1 difference), in that case, compare the current array with the max solution so far if the current solution is better just update the max solution.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 גלעד ברקן
Solution 2 Augusto Ferreira
Solution 3