给出仅包含0和1的数组作为输入。您可以选择数组i和j的任意两个索引并翻转它们之间的所有元素(即0-> 1和1-> 0)。找到翻转后可以获得的数组的最大总和。 例如:对于[0,1,0,0,1,0],答案是4.(从索引2翻到3)。
这是我的方法:
1)找到数组中所有索引的前缀sum(保持sum [i])
2)翻转原始数组中的所有位
3)使用Kadane的算法找到最大子阵列和MAXSUM。让max子阵列的起始和结束索引为i和j。
4)答案是sum(i-1)+ MAXSUM + sum(n-1)-sum(j)。
请告诉我我的方法是否正确。
答案 0 :(得分:2)
实际上,您可以通过阵列一次性轻松地完成此操作。您可以跟踪当前翻转位的范围有多好。只要您处于正数,当前范围就可以预先设置到任何后续范围。但是一旦你达到零或负,你应该放弃你的范围并开始新的范围。
例如,如果您发现翻转指数0..5会产生+4,那么这很好,您可能希望将0..5作为范围的一部分,因为如果您也是要翻转指数6..X。但是如果0..5导致-1,你想不使用0..5因为这只会降低你的分数。那么在那时你将从6点开始。也许它在代码中更容易看到。这是一个C版本,可以一次解决问题:
// Returns best range (start..end) to flip, and best score achieved.
static void findRange(const int *array, int *pStart, int *pEnd, int *pScore)
{
int start = 0;
int best = 0;
int i = 0;
int diff = 0;
int base = 0;
int bestStart = -1;
int bestEnd = -1;
// Count the number of 1s in the array already.
for (i=0;i<N;i++)
base += array[i];
// Run through the array, keeping track of "diff", which is how much
// we have gained by flipping the bits from "start" to "i".
for (i=start=0;i<N;i++) {
// Flip the number at i.
if (array[i] == 0)
diff++;
else
diff--;
// If this range (from start to i) is the best so far, remember it.
if (diff > best) {
bestStart = start;
bestEnd = i;
best = diff;
}
// If we get to a zero or negative difference, start over with a
// new range starting from i+1.
if (diff <= 0) {
start = i+1;
diff = 0;
}
}
*pStart = bestStart;
*pEnd = bestEnd;
*pScore = base + best;
}
编辑:在阅读了关于Kadane的算法之后,事实证明我写的内容是等效的,使用Kadane在修改过的数组上找到最大子数组,在这个数组中将每个0切换为1,每个1切换为-1