Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 查找二进制字符串中最长的正子字符串_Algorithm_Math_Data Structures - Fatal编程技术网

Algorithm 查找二进制字符串中最长的正子字符串

Algorithm 查找二进制字符串中最长的正子字符串,algorithm,math,data-structures,Algorithm,Math,Data Structures,假设我有一个类似于100110001010001的字符串。我希望找到这样的子字符串: 尽可能长 总正和大于0 因此,最长的子字符串,其1s多于0s 例如,对于上面的字符串1001100010100001,它应该是:[10011]000[101]000[1] 事实上,找到它们的总长度是令人满意的,在这种情况下:9 不幸的是,我没有线索,怎么能不以暴力的方式做到这一点。有什么想法吗?动态规划 我们有一根绳子。如果是肯定的,那就是我们的答案。否则,我们需要修剪每一端,直到它变为正值,并找到每种修剪

假设我有一个类似于
100110001010001
的字符串。我希望找到这样的子字符串:

  • 尽可能长
  • 总正和大于0
因此,最长的子字符串,其1s多于0s

例如,对于上面的字符串
1001100010100001
,它应该是:
[10011]000[101]000[1]

事实上,找到它们的总长度是令人满意的,在这种情况下:9

不幸的是,我没有线索,怎么能不以暴力的方式做到这一点。有什么想法吗?

动态规划

我们有一根绳子。如果是肯定的,那就是我们的答案。否则,我们需要修剪每一端,直到它变为正值,并找到每种修剪模式。对于每个长度(N-1,N-2,N-3)等等,我们有N个长度的可能路径(从a开始修剪,从b开始修剪),每个路径都给我们一个状态。当状态变为正时,我们已经找到了子字符串

所以有两个整数列表,表示如果我们完全从a或完全从b修剪,会发生什么。然后回溯。如果我们从a修剪1,我们必须从b修剪所有剩余的,如果我们从a修剪2,我们必须从b修剪少一个。有没有一个答案可以让我们做出肯定的回答

我们可以很快消除,因为答案必须是最大值,要么是a的最大微调,要么是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 */
N=长度(字符串);
Nones=countone(字符串);
Nzeros=N-非;
如果(非>非)
返回字符串
向量割;
向量cutb;
int besta=非-Nzeros;
int bestb=非-Nzeros;
cuta.向后推(besta);
切口b.推回(最佳b);
贝斯蒂亚=0;
bestib=0;
对于(i=0;i最佳)
{
besta=背部切口();
贝斯蒂亚=我;
}
if(cutb.back()>bestb)
{
bestb=缩回();
bestib=i;
}
//检查,从a或b中完全切下的部分会给我们带来阳性吗
如果(besta==1)
答案=子字符串(字符串,bestia,N);
如果(最佳B==1)
答案=子字符串(字符串,0,N-bestib);
//如果不是,则是从当前位置到当前位置的组合切割
//另一个分布的峰值会给我们带来积极的影响吗?
如果(非-Nzeros+besta+cutb.back()==1)
{
答案=子字符串(字符串,最佳,N-i);
}
if(Nones-Nzeros+cuta.back()+bestb==1)
{
答案=子字符串(字符串,i,N-最佳bi);
}
}
/*如果我们到这里,字符串都是零,没有正的子字符串*/
这是未经测试和最终检查是有点棘手,我可能有 在某个地方出错,但该算法应该或多或少能正常工作
如上所述。

正如现在发布的,您的问题似乎有点不清楚。“尽可能长”的有效子字符串的总长度可能意味着不同的事情:例如,在其他选项中,它可以是(1)每个索引左侧最长有效扩展名的列表(这将允许列表中的重叠),(2)非重叠最长左扩展名的最长组合,(3)非重叠有效子字符串的最长组合(其中每个子字符串不一定是最长的)

我将概述(3)的方法,因为它很容易转换为(1)或(2)。可以在
O(n log n)
time和
O(n)
附加空间中(对于
O(n)
time中最长的有效子字符串,请参见此处:)从每个索引中查找大于零的最长左扩展名。通过这种预处理,可以使用动态规划在稍微优化的
O(n^2)
时间和
O(n)
额外空间中找到有效的、不重叠的子字符串的最长组合

我们首先遍历字符串,存储表示部分和的和,包括
s[i]
,将零计数为
-1
。我们在二叉树中插入每个部分和,其中每个节点还存储值出现的索引数组,以及小于节点值的值的最左侧索引。(如果前缀sum up to
b
大于前缀sum up to
A
,则从
s[A]
s[b]
的子字符串的值大于零)如果树中已有值,则将索引添加到节点的索引数组中

因为我们是从左到右遍历,只有当一个新的最低值插入到树中时,较低值的最左边的索引才会更新,并且它只会针对具有先前最低值的节点进行更新。这是因为任何具有较低值的节点都不需要更新;如果树中已经存在任何值较低的节点,则任何值较高的节点都会存储最早插入的节点的索引

每个索引左边最长的有效子字符串扩展到最左边的索引,其前缀和较低,可以在树中轻松查找


要获得最长的组合,让
f(i)
表示索引
i
之前的最长组合。然后
f(i)
等于可以索引
j
添加到
f(j-1)

的每个有效左扩展名的最大长度。请更正我,但在100110001010001中,与您的条件匹配的最长子序列是100110001010001。@Robert,刚才编辑过它。子字符串,你是对的。找到一个好的算法总是从彻底分析你的需求开始,这样你就能很好地理解它们。正如你所说,罗伯特仍然是对的。很明显,这不是你想要的,但是试着准确地表达你想要的。这将使您(和我们)得到一半的答案。我认为您应该简单地迭代整个字符串,并保存第一次和最后一次出现的“1”的索引。然后你可以简单地从最后一个索引中减去第一个索引,再加上1,你就得到了你想要的最长子序列的长度