相同数量的0和1s算法

时间:2015-07-04 14:26:30

标签: algorithm language-agnostic time-complexity complexity-theory

我试图解决以下问题:

  

给定一个只包含0和1的二进制数组,找到包含0和1的等号的最大子数组。

     

示例:

     

输入:arr [] = {1,0,1,1,1,0,0,0,1}   输出:1到8(输出子数组的起始和结束索引)

我只能想到一个O(n ^ 2)解决方案(即在每个子位置启动数组,然后检查所有剩余元素是否具有相同数量的0和1)的明显方法。

有人可以为这个问题找到更好的解决方案吗?

2 个答案:

答案 0 :(得分:0)

我相信这可以使用权重平衡二叉树结构在O(n)中解决。

答案 1 :(得分:0)

关于措辞的一个小小的注释:你说找到 最长的子阵列,这意味着唯一性,但即使在你的例子中也有不止一个(0到7或1到8)。它将更好地表示为“找到最大长度的 a 子阵列”或类似的。但这不是问题。

对于更快的算法,首先通过用-1替换0的每个实例来定义新数组swap。这可以在O(n)时间内完成。对于你的例子,我们会有

1, -1, 1, 1, 1, -1, -1, -1, 1

现在定义另一个数组sum,使sum[i]是所有值swap[0], swap[1], ..., swap[i]的总和。等价地,

sum[0] = swap[0];
for i > 1, sum[i] = sum[i-1] + swap[i]

O(n)时间再次出现。所以你的例子变成了

1, 0, 1, 2, 3, 2, 1, 0, 1

现在进行观察。如果1的数量等于子阵列(arr[i], ..., arr[j])中的0的数量,那么在第一个新数组中,1s将取消相应的-1,因此所有值(swap[i], ..., swap[j])的总和将相等到0.但这等于

swap[0] + swap[1] + ... + swap[j] - (swap[0] + swap[1] + ... + swap[i-1]),

又等于

sum[j] - sum[i-1].

虽然注意,如果i等于0,我们必须小心,否则我们不在数组的范围内。这是一个易于实现的检查。

现在我们已将问题简化为在sum[j] - sum[i-1]等于0时查找。但这相当于找到值ji,使sum[j] = sum[i-1]

由于我们知道sum中的所有值都位于-n和n之间(其中n是初始数组的大小),您现在可以创建另一对数组min和{ {1}}大小为2n + 1。此处,maxmin的索引对应max的潜在值,其中sum将包含min[0]的最小索引isum[i] = -n将包含min[1]的最小索引i,依此类推。同样,max将保持最大的索引。这也可以在线性时间内实现。完成此步骤后,sum[i] = -n+1max[i]将对应min[i]的值。

现在你所要做的就是找到sum[min[i]] = i = sum[max[i]]的最大值,这将从上面max[k] - min[k]i = min[k] + 1给出,包含相同数字的最大子数组的索引0和1。这也是O(n)。

我有点粗略地描述了这一点,所以当i = 0时你必须小心,但这很容易解释。然而,每一步都是O(n),所以你的算法更有效率。