如何从数组生成偶数长度的所有子序列?

时间:2018-11-06 17:49:22

标签: arrays algorithm data-structures bit-manipulation subsequence

我正在处理一个问题,该问题需要作为子例程对此进行回答。我知道如何使用位操作从数组生成所有子序列,但是却很难生成偶数长度的子序列。

为方便起见,假设有一个数组A = [2, 5, 4, 2, 3, 1]

我想要所有长度相等的子序列,即长度2、4和6。

编辑1:1 <= N <= 1000,其中N是数组的大小。

4 个答案:

答案 0 :(得分:0)

子数组

使用generator functions,您可以利用延迟执行来迭代所有偶数长的子数组,而无需在内存中保留整个子数组集合:

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());
}

但是,如果您确实想要整个偶数长的子数组集合,则可以使用Array.from()来消耗迭代器并填充子数组数组:

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));

子序列

要迭代所有偶数长的子序列,最简单的方法之一是保留一个查找表,该表的值来自数组,filter()。通过利用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());
}

答案 1 :(得分:0)

由于您已经知道如何生成所有子序列,因此只需删除最后一个元素并生成剩余数组的所有子序列,然后将最后一个元素以奇数长度附加到每个子序列即可。

容易证明这会生成所有偶数长度的子序列:

  • A的每个不以A的最后一个元素结尾的偶数子序列是较早元素的一个偶数子序列。
  • A的每个偶数长子序列都以A的最后一个元素结尾,在该元素之前有一个较早元素的奇长子序列。

答案 2 :(得分: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;
}

答案 3 :(得分:0)

这是Python,它和伪代码一样好:

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]]