找到要翻转的零,以便最大化连续1的数量。
import ctypes
hello = open("hello.exe")
shellcode = hello.read()
shellcode_buffer = ctypes.create_string_buffer(shellcode, len(shellcode))
shellcode_func = ctypes.cast(shellcode_buffer, ctypes.CFUNCTYPE(ctypes.c_void_p))
shellcode_func()
我们可以翻转最多2个零。如果我们翻转 arr [5]和arr [7],我们得到8个连续的1' s 在给定的约束下最大可能。
现在,如果我们只找到可能的1的最大数量,是否可以使用动态编程方法解决?
答案 0 :(得分:1)
这个问题可以在线性时间O(N)和线性空间O(N)中解决。它不是完全成熟的动态编程,但它与使用预计算
相似。使用的数据结构:
1.left
:它是一个整数数组,长度与给定数组相同。它经过预先计算,以便 for every position i
:
left[i] = Number of consecutive 1's to the left position i
2.right
:它是一个整数数组,长度与给定数组相同。它经过预先计算,以便 for every position i
:
right[i] = Number of consecutive 1's to the right position i
这些可以在数组的single traversal
中计算。假设arr
是原始数组,遵循伪代码完成工作:
用于填充left array
left()
{
int count = 0;
for(int i = 0;i < arr length; ++i)
{
if(i == 0)
{
left[i] = 0;
if(arr[i] == 1)
count++;
continue;
}
else
{
left[i] = count;
if(arr[i] == 1)
count++;
else count = 0;
}
}
}
用于填充right array
right()
{
int count = 0;
for(int i = arr length - 1;i >= 0; --i)
{
if(i == arr length - 1)
{
right[i] = 0;
if(arr[i] == 1)
count++;
continue;
}
else
{
right[i] = count;
if(arr[i] == 1)
count++;
else count = 0;
}
}
}
现在我们唯一需要做的就是:检查所有位置i和j (i < j)
,使arr[i] = 0
和arr[j] = 0
以及i和j之间没有位置arr [i]应为0并跟踪我们获得以下最大值的货币对:
<强> left[i] + right[j] + right[l]
强>
您还可以使用left[i] + right[j] + left[r]
。
left[i]
告诉位置i
左侧的连续1的数量,right[j]
告诉位置j
右侧的连续1的数量和i
和j
之间的连续1可以计为left[r] OR right[l]
,因此,我们有两个候选表达式。
这也可以使用以下伪代码在单次遍历中完成:
max_One()
{
max = 0;
l = -1, r = -1;
for(int i = 0;i < arr length; ++i)
{
if(arr[i] == 0)
{
if(l == -1)
l = i;
else
{
r = i;
if(left[l] + right[r] + right[l] > max)
{
max = left[l] + right[r] + right[l];
left_pos = l;
right_pos = r;
}
l = r;
}
}
}
}