我们假设我有一个像100110001010001
这样的字符串。我想找到这样的子串:
所以最长的子串,比0更多。
例如,对于100110001010001
以上的字符串,它将是:[10011]000[101]000[1]
实际上找到那些的总长度是令人满意的,在这种情况下:9。
不幸的是我不知道怎么办,不能用蛮力的方式来做。有什么想法吗?
答案 0 :(得分:0)
动态编程。
我们有一个字符串。如果是积极的,那就是我们的答案。否则,我们需要修剪每一端,直到它变为正,并找到每个修剪模式。因此,对于每个长度(N-1,N-2,N-3)等,我们已经获得了N长度的可能路径(来自a的修剪,来自b的修剪),每个路径都给出了一个状态。当状态变为正数时,我们发现了子串。
所以有两个整数列表,表示如果我们完全从a或完全从b修剪会发生什么。然后回溯。如果我们从a中修剪1,我们必须从b修剪所有其余部分,如果我们从a修剪两个,我们必须从b减少一个。有答案可以让我们积极吗?
我们可以快速消除,因为答案必须是最大值,或者从b的最大修剪或最大修剪。如果另一个修饰使我们变得积极,那就是结果。
伪代码:
N = length(string);
Nones = countones(string);
Nzeros = N - Nones;
if(Nones > Nzeroes)
return string
vector<int> cuta;
vector<int> cutb;
int besta = Nones - Nzeros;
int bestb = Nones - Nzeros;
cuta.push_back(besta);
cutb.push_back(bestb);
bestia = 0;
bestib = 0;
for(i=0;i<N;i++)
{
cuta.push_back( string[i] == 1 ? cuta.back() - 1 : cuta.back() +1);
cutb.push_back( string[N-i-1] == 1 ? cutb.back() -1 : cutb.back()+1);
if(cuta.back() > besta)
{
besta = cuta.back();
bestia = i;
}
if(cutb.back() > bestb)
{
bestb = cutb.back();
bestib = i;
}
// checks, is a cut from wholly from a or b going to send us positive
if(besta == 1)
answer = substring(string, bestia, N);
if(bestb == 1)
answer = substring(string, 0, N - bestib);
// if not, is a combined cut from current position to the
// the peak in the other distribution going to send us positive?
if(Nones - Nzeros + besta + cutb.back() == 1)
{
answer = substring(string, bestai, N - i);
}
if(Nones - Nzeros + cuta.back() + bestb == 1)
{
answer = substring(string, i, N - bestbi);
}
}
/*if we get here the string was all zeros and no positive substring */
这是未经测试的,最后的检查有点繁琐,我可能会 在某个地方犯了错误,但算法应该或多或少地起作用 如上所述。
答案 1 :(得分:0)
现在发布,您的问题似乎有点不清楚。 “尽可能长”的有效子串的总长度可能意味着不同的东西:例如,在其他选项中,它可以是(1)每个索引左侧最长有效扩展的列表(这将允许重叠)在列表中),(2)非重叠这种最长左扩展的最长组合,(3)非重叠有效子串的最长组合(其中每个子串不一定是最长的)。
我将概述(3)的方法,因为它很容易转换为(1)或(2)。在O(n log n)
时间和O(n)
额外空间中查找每个索引中包含多于零的最长左延伸,可以在O(n)
时间内完成(对于O(n^2)
时间内最长的有效子字符串,请参见此处: Finding the longest non-negative sub array)。通过该预处理,可以在稍微优化O(n)
时间和s[i]
额外空间的动态编程中找到有效,非重叠子串的最长组合。
我们首先遍历字符串,存储表示部分总和的总和,包括-1
,将零计数为s[a]
。我们在二叉树中插入每个部分和,其中每个节点还存储值出现的索引数组,以及值小于节点值的最左侧索引。 (如果前缀总和为s[b]
大于b
的前缀总和,则a
到f(i)
的子字符串比0更多。)如果值为已经在树中,我们将索引添加到节点的索引数组。
由于我们从左到右遍历,只有当新的最低值插入到树中时,最左边的索引值才会更新 - 并且它仅针对具有先前最低值的节点进行更新。这是因为任何具有较低值的节点都不需要更新;如果任何具有较低值的节点已经在树中,则任何具有较高值的节点都已经存储了最早插入的节点的索引。
每个索引左侧最长的有效子字符串扩展到最左边的索引,前缀总和较小,可以在树中轻松查找。
要获得最长的组合,请i
代表索引f(i)
之前的最长组合。然后j
等于可以将f(j-1)
添加到SELECT a.originalID, b.part
from #1 a
join #2 b
on a.area = b.area
where not exists (select * from #3 c where c.originalID = a.originalID and c.part = b.part)
的每个有效左扩展的最大长度。