【问题标题】:How to determine if chunks of a value could fit into an array如何确定值的块是否可以放入数组
【发布时间】:2018-08-09 13:13:49
【问题描述】:

给定一个任意长度的1s 和0s 输入数组,例如:

[0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0]

如果大小为n0s 的块可以放入输入中,我如何(最有效地)计算一个新的数组详细信息?

示例

现在的输出意味着

  • 1 == '是的,大小可以放在这里的零块'
  • 0 == '无法容纳这样大小的块'

  • 块大小 = 1 ([0]): [1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
  • 块大小 = 2 ([0,0]): [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
  • 块大小 = 3 ([0,0,0]): [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
  • 块大小 = 4 ([0,0,0,0]): [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

我使用的是 ES6,所以任何语言功能都可以。

编辑:

输出不应该只是一个“是”/“否”,一个大小为“n”的块可以放在这个数组中。更具体地说,它需要是一个相同长度的数组,其中一个“1”/“真”数组值代表任一:

  • 是的,一个大小为“n”的块可以从这里开始并适合这里,
  • 是的,这个槽可以包含一个大小为“n”的块,在它之前开始

关于第二点,这意味着块大小为 3:

input = [1, 0, 0, 0, 0, 1];

output = [0, 1, 1, 1, 1, 0];

编辑 2:

这是我想出的功能,但似乎效率很低:

const calculateOutput = (input, chunkSize) => {
  const output = input.map((value, index) => {
    let chunkFitsHere = false;

    const start = (index - (chunkSize) >= 0) ? index - (chunkSize) : 0;
    const possibleValues = input.slice(start, index + chunkSize);
    possibleValues.forEach((pValue, pIndex) => {
      let consecutives = 0;
      for (let i = 0; i < possibleValues.length - 1; i += 1) {
        if (consecutives === chunkSize) {
          break;
        }
        if (possibleValues[i+1] === 0) {
          consecutives += 1;
        } else {
          consecutives = 0;
        }
      }
      if (consecutives === chunkSize) {
        chunkFitsHere = true;
      }
    });
    return chunkFitsHere ? 1 : 0;
  });
  return output;
};

【问题讨论】:

  • 请添加块大小如何影响结果。除此之外,请添加你的代码,你试过了。
  • 我将澄清上述内容并添加一个我很快尝试过的适当示例 - (必须为问题抽象出我原来的问题)

标签: javascript arrays algorithm ecmascript-6


【解决方案1】:

您可以通过反转数组来计算连接的空闲位置,并为映射的最后一个返回值取一个标志。

最终映射之前和之后的数组,取决于n

 1  0  4  3  2  1  0  0  2  1  0  0  0  3  2  1  0  2  1  array with counter
 1  0  4  4  4  4  0  0  2  2  0  0  0  3  3  3  0  2  2  array same counter
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --  ------------------
 1  0  1  1  1  1  0  0  1  1  0  0  0  1  1  1  0  1  1  n = 1
 0  0  1  1  1  1  0  0  1  1  0  0  0  1  1  1  0  1  1  n = 2
 0  0  1  1  1  1  0  0  0  0  0  0  0  1  1  1  0  0  0  n = 3
 0  0  1  1  1  1  0  0  0  0  0  0  0  0  0  0  0  0  0  n = 4

function chunk(array, n) {
    return array
        .slice()
        .reverse()
        .map((c => v => v ? c = 0 : ++c)(0))
        .reverse()
        .map((l => v => l = v && (l || v))(0))
        .map(v => +(v >= n));
}

var array = [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0];

console.log(chunk(array, 1).join(' '));
console.log(chunk(array, 2).join(' '));
console.log(chunk(array, 3).join(' '));
console.log(chunk(array, 4).join(' '));

如果您只喜欢最后一个映射,请删除最后两个 map 并使用

.map((l => v => l = +(v && (v >= n || l)))(0));

用于最终映射。

【讨论】:

  • 这个解决方案很漂亮,告诉我Array.prototype.reverse() 存在!计数器也非常有助于说明它如何检查周围的空间。
【解决方案2】:

您可以遍历数组一次,计算一系列零的长度。如果足够长,则用相同长度的 1 序列填充输出。

请注意,您可以同时为不同的块长度填充输出(在行索引不超过zerolen的二维数组行中填充块)

Python 代码:

def zerochunks(a, n):
    l = len(a)
    result = [0] * l   #list of l zeros

    zerolen = 0
    for i in range(l + 1):
        ### Short circuit evaluation to shorten code
        if (i==l) or (a[i] != 0):   
            if (zerolen >= n):   #series of zeros is finished here
                for j in range(i - zerolen, i):
                    result[j] = 1
            zerolen  = 0
        else:
            zerolen += 1

    return result

print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 1))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 2))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 3))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 4))
print(zerochunks([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 5))

>>> 
[1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
[0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1]
[0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
[0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

以及用于获取所有块在 maxn 范围内的数组的函数:

def zerochunksall(a, maxn):
    l = len(a)
    result = [[0] * l for i in range(maxn)]

    zerolen = 0
    for i in range(l + 1):
        if (i==l) or (a[i] != 0):
            for k in range(0, zerolen):
                for j in range(i - zerolen, i):
                    result[k][j] = 1
            zerolen  = 0
        else:
            zerolen += 1

    return result

print(zerochunksall([0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0], 5))
 >>
[[1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1],
 [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], 
 [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0], 
 [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

【讨论】:

  • 谢谢你——理想情况下,解决方案需要在 JS 中帮助他人。虽然算法很有趣,但会考虑将其移植到 JS 中!
  • 我不知道如何正确组织 JS 数组/列表,所以决定用 Python 演示工作代码。希望移植很简单。
【解决方案3】:
function fit(input, n) {
    var output = [];
    for(var i = 0; i < input.length; i++) {
        var fit = true;
        for(var j = i; j < i + n; j++) {
            if(j >= input.length || input[j]) {  // either over the array size or occupied
                fit = false;
                break;
            }
        }
        output.push(fit);
    }
    return output;
}

var input = [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0];
console.log(fit(input, 1).map(v => +v));
console.log(fit(input, 2).map(v => +v));
console.log(fit(input, 3).map(v => +v));
console.log(fit(input, 4).map(v => +v));

输出

[ 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1 ]
[ 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 ]
[ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]
[ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]

虽然这些似乎与您的预期输出不完全匹配,但这可能是因为我假设数组中的标志应该标记块的开始(即您可以在数组中从这个位置)。

(见下文,其中 e = 您的预期结果,n = 我的算法的输出。)

input = [ 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0 ]
e = 2 = [ 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1 ]
n = 2 = [ 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 ]
                         ====  ====  ====              ====

【讨论】:

  • 谢谢你——这是最接近的,因为我想根据我的问题示例输出一个数组。不过,我需要在我的问题中澄清一下,因为输出中的 1 可能意味着“是的,这个插槽可能是一个块的开始,或者也是一个可行块的一部分”
【解决方案4】:

您可以使用array.prototype.some 来检查块是否适合输入数组的某个索引。要检查具有实际长度的块是否适合,您可以使用array.prototype.every

var input = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0];
var chunk = [0,0,0];
var res = input.some((e, i) => chunk.every((c, j) => input[i + j] === c));
console.log(res);

var input = [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0];
var chunk = [0, 0, 0, 0, 0, 0, 0, 0];
var res = input.some((e, i) => chunk.every((c, j) => input[i + j] === c));
console.log(res);

【讨论】:

    【解决方案5】:

    您可以使用some 方法,然后如果当前元素是0,您可以从当前索引切分数组的一部分并检查其是否全为零。

    const data = [0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0]
    
    function check(arr, n) {
      let chunk = Array(n).fill(0).join('');
      return arr.some((e, i) => e === 0 && arr.slice(i, i + n).join('') == chunk)
    }
    
    console.log(check(data, 3))
    console.log(check(data, 4))
    console.log(check(data, 5))

    【讨论】:

      猜你喜欢
      • 2014-01-08
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 2015-12-27
      • 2018-05-25
      • 1970-01-01
      • 2017-03-03
      • 2017-04-01
      相关资源
      最近更新 更多