给出一个大小为n的数组,该数组包含0和1以及两个操作,求出使所有元素均为0的最小操作数。
操作:
如果第(i + 1)个元素为1,并且从第(i + 2)到所有连续元素为0或不存在,则翻转第i个元素(如果i + 2 = n)。 (0 <= i <= n-2)
例如,以上操作适用于:
在此元素上
|
V
1100
或
在此元素上
|
V
1011
n <= 50
例如 输入: 1,0,0,0
输出: 15
说明:
1000-> 1001-> 1011-> 1010-> 1110-> 1111-> 1101-> 1100-> 0100-> 0101-> 0111-> 0110-> 0010-> 0011-> 0001-> 0000 < / p>
答案 0 :(得分:4)
在除具有所有0
的数组之外的任何数组上,只能执行两个操作。翻转第n个元素,或翻转数组中最后一个1
之前的元素。
我们不需要考虑仅第一个元素为1
的边缘情况,因为我们可以在数组的开头添加任意数量的零,并且它不会改变结果,即[1, 0, 0, 0]
和[0, 1, 0, 0, 0]
需要相同数量的最小操作才能成为所有0
。
这意味着,在0
和1
的每个序列上,其中一个操作将比0
更近一步,而另一个操作则更进一步。
这些观察的结果是我们实际上拥有一个非常类似于二进制的数值系统,并且每个操作都可以看作是将数字递增或递减1,这意味着对于0
和1
的每个序列s有一个等效的二进制数和十进制数,即该数字与0之间的步数。
我发现该系统与二进制文件之间的关系如下:
如果我们从头到尾遍历数组并翻转1
之后的每个元素,我们将获得等效的二进制文件。该操作需要就地完成,这意味着我们在迭代时会更改数组本身,并且每次迭代的结果都会影响下一次迭代。我没有证明这是正确的原因,也许有人可以提供证明。
综上所述,算法本身很简单。这是在python中:
a = [1, 0, 0, 0]
# convert to equivalent binary
for i in range(1, len(a)):
a[i] = int(not a[i]) if a[i-1] == 1 else a[i]
# convert to decimal
bin_str = ''.join(map(str, a))
print(int(bin_str, 2))