0

I am dealing with a problem and that problem requires the answer to this as a subroutine. I know how to generate all subsequences from an array using bit manipulation but struggling to generate subsequences of even length.

For the sake of example, assume that there is an array A = [2, 5, 4, 2, 3, 1]

I want all the subsequences of even length i.e., of length 2, 4, and 6.

Edit 1: 1<=N<=1000 where N is the size of the array.

Anonymous
  • 63
  • 2
  • 9

4 Answers4

0

Subarrays

Using generator functions, you can take advantage of deferred execution to iterate all of the even-lengthed subarrays without retaining the entire collection of subarrays in memory:

function * subarrays (array) {
  for (let length = 1; length <= array.length; length++) {
    for (let index = 0; index + length <= array.length; index++) {
      yield array.slice(index, index + length);
    }
  }
}

const filter = predicate => function * (iterator) {
  for (const value of iterator) {
    if (predicate(value)) yield value;
  }
};

const even = filter(subarray => subarray.length % 2 === 0);


for (const subarray of even(subarrays ([2, 5, 4, 2, 3, 1]))) {
  console.log(subarray.join());
}

However, if you do want the entire collection of even-lengthed subarrays, you can use Array.from() to consume the iterator and populate an array of subarrays:

function * subarrays (array) {
  for (let length = 1; length <= array.length; length++) {
    for (let index = 0; index + length <= array.length; index++) {
      yield array.slice(index, index + length);
    }
  }
}

const filter = predicate => function * (iterator) {
  for (const value of iterator) {
    if (predicate(value)) yield value;
  }
};

const even = filter(subarray => subarray.length % 2 === 0);
const result = Array.from(even(subarrays([2, 5, 4, 2, 3, 1])));

console.log(JSON.stringify(result));

Subsequences

To iterate all even-lengthed subsequences, one of the easiest methods is to keep a lookup table of which values to filter() from the array. We can achieve this with fairly minimal memory overhead by leveraging a Uint32Array:

function _increment (uint32Array) {
  for (let index = 0; index < uint32Array.length; index++) {
    // use unsigned integer overflow to
    // perform carry in base 2**32 addition
    if (++uint32Array[index]) return;
  }
}

function * subsequences (array) {
  const lut = new Uint32Array(Math.ceil(array.length / 32));
  let subsequence;

  while (true) {
    yield subsequence = array.filter(
      (_, index) => (lut[index >>> 5] >>> (index % 32)) & 1
    );

    if (subsequence.length === array.length) return;
    _increment(lut);
  }
}

const filter = predicate => function * (iterator) {
  for (const value of iterator) {
    if (predicate(value)) yield value;
  }
};

const even = filter(({ length }) => (length > 0) && (length % 2 === 0));

for (const subsequence of even(subsequences([2, 5, 4, 2, 3, 1]))) {
  console.log(subsequence.join());
}
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
0

Since you already know how to generate all subsequences, then just remove the last element and generate all subsequences of the remaining array, but append the last back to each subsequence with an odd length.

Easy to prove that this generates all the even-length subsequences:

  • Every even-length subsequence of A that does not end in the last element of A, is an even-length subsequence of the earlier elements.
  • Every even-length subsequence of A that does end in the last element of A, has that element preceded by an odd-length subsequence of the earlier elements.
Matt Timmermans
  • 53,709
  • 3
  • 46
  • 87
0
#include <stdio.h>
#define N 4

const int A[] = { 2, 5, 4, 2, 3, 1, -1 };
int out[1000];

void gen(const int *p, int *pout) {
  if(pout - out < N) {
    while((*pout = *p++) > 0)
      gen(p, pout + 1);
  } else { // print output
    for(const int *o = out; o < pout; o++)
      printf("%d ", *o);
    putchar('\n');
  }
}

int main(int argc, char **argv) {
  gen(A, out);
  return 0;
}
olegarch
  • 3,670
  • 1
  • 20
  • 19
0

Here's Python, which is as good as pseudocode:

def even_subsequences(L): 
    # yield the empty subsequence
    yield []

    # iterate over subsequence starting points
    for i in range(len(L)): 
        # subsequence end point is the starting point plus an even number
        for j in range(i+2, len(L)+1, 2):
            # slice the list
            yield L[i:j] 


>>> list(even_subsequences([1,2,3,4,5,6]))
[[],
 [1, 2],
 [1, 2, 3, 4],
 [1, 2, 3, 4, 5, 6],
 [2, 3],
 [2, 3, 4, 5],
 [3, 4],
 [3, 4, 5, 6],
 [4, 5],
 [5, 6]]
BallpointBen
  • 9,406
  • 1
  • 32
  • 62