找到二进制字符串中最大的零运行的高效算法?

时间:2015-06-09 03:57:15

标签: python algorithm

我正在寻找一种有效的算法来查找二进制字符串中最长的零运行。我的实现是在Python 2.7中,但我需要的只是算法的概念。

例如,给定'0010011010000',函数应返回4.

7 个答案:

答案 0 :(得分:8)

我认为没有什么比在单个字符串上传递更好,计算当前序列长度(并更新最大值)。

如果用"二进制字符串"你的意思是原始位,你可以一次读取一个字节并在那里提取8位(使用位移或屏蔽)。这并不会改变整体算法或其复杂性。

答案 1 :(得分:2)

应该可以击败明显的算法。这个想法是,如果你已经有一个长度为0的0并且你看到两个1不超过N个位置,你不需要检查它们之间的任何位置。因此,从末尾而不是从头开始检查候选零序列。在最糟糕的情况下,你只需检查所有元素,就像在天真的方法中一样,但平均来说它会小于那个。

所以算法就像这样(伪代码,未经测试)

  maxrun = 0
  curpos = 0
  runstart = 0
  runend = 0

  while curpos + maxrun < array.length
      broken = false
      for i = curpos + maxrun, i >= curpos and not broken, --i
        if array[i] == 1
          broken = true
          curpos = i + 1

      if not broken
        runstart = curpos
        # found a longer run of 0s
        # now extend it to the end
        maxrun++
        curpos += maxrun
        while curpos < array.length and array[curpos] == 0
          maxrun++
        # ok found the 1 at the right end of the run
        # go to the next position and start over
        runend = curpos
        curpos++

 # the longest run of 0s is [runstart, runend)

答案 2 :(得分:1)

为了找到二进制字符串中连续的最大零,我建议如下:

int maxConsecutiveZeros(String binaryString) {
    int maxcount = Integer.MIN_VALUE;
    int currcount = 0;
    for(int i=0; i < binaryString.length(); i++) {
        if(binaryString.charAt(i) == '0') {
            currcount++;
        } else {
            maxcount = Math.max(currcount, maxcount);
            currcount = 0;
        }
    }
    return maxcount;
}

您应该单独处理binaryString以零结尾的情况。将该部分添加到提供的大纲中,您就完成了。

这种方法的复杂性在二进制字符串的长度上是线性的。

答案 3 :(得分:1)

这取决于你的效率是什么意思。

如果您的目的是最大限度地减少运行时间,那么您基本上必须逐个字符地检查字符串,分析连续零的运行并跟踪最长的,如:

def longRunZeros(s):
    big = 0
    curr = 0
    for c in s:
        if c == '0':
            curr += 1
        else:
            if curr > big:
                big = curr
            curr = 0
    if curr > big:
        big = curr
    return big

print longRunZeros('0010011010000')

如果您正在谈论程序员效率,请执行以下操作:

def longRunZeros(s):
    return max(len(i) for i in s.split('1'))

代替。

它不一定能以最快的速度运行,但它可以让你有更多的时间,也许可以用来分析你是否需要这个操作的原始速度。它几乎可以肯定不那么容易出错。

至于你是否需要速度,请考虑一下。对于25M字符串,逐字符方法需要2.826秒的CPU时间进行一百万次迭代。对于相同的工作负载 1 split方法需要3.186秒。

所以,除非你的字符串长度超过25M或者你需要做的时间超过一百万次,否则它不会产生太大的影响,我倾向于选择对于我作为开发人员来说更容易的方法。

附录:在支持这里无关的差异表现之后,我觉得有点虚伪地提到John La Rooy在评论中显示的另一种方法实际上似乎比我的两种方法都要快一些。

但是,为了完整起见,我还会用吊索和箭头指出那一个:

def longRunZeros(s):
    return len(max(s.split('1')))

这似乎是大约1.092的平均值,这是上述逐个字符情况的两倍。

1 在我的环境中,这些数字是五次运行的平均值,我不保证他们会在其他任何地方举行。

如果您参与优化工作,您应该知道它应该在您的实际环境中进行衡量,而不是依赖于某些随机的说法 - 但是非常好看的人在互联网上: - )

答案 4 :(得分:1)

编译的正则表达式可能会快得多,但我还没有真正测试过它。尽管如此:

>>> binstr = '0010011010000'
>>> import re
>>> zeros = re.compile(r'0+')
>>> max(len(m) for m in zeros.findall(binstr))
4

答案 5 :(得分:0)

好的,正如有人提到的,它的类型是 String ,那么我认为你无法逃避O(| N |)这是I / O时间。我在这里只想说它是一个整数,然后你可以做得更快,例如:

#include<bits/stdc++.h>
using namespace std;
int n;

void binary(int x){
    if(x){
        binary(x>>1);
        if(x&1) putchar('1');
        else putchar('0');
    }

}

int main() {
    scanf("%d", &n);
    while(n){
        binary(n);
        puts("");
        int x = log2(n&-n);
        printf("Zero range: %d\n", x);
        n >>= (x+1);
    }
    return 0;
}

忽略打印部分,我认为是O(lg N)? (警告:因为这是处理整数,不考虑填充零,但它应该不难)

答案 6 :(得分:0)

这有点乱,我知道如果我多想一点,我可以改善结局

def solution(N):
    y = [int(x) for x in bin(N)[2:]]
    lst,zero = [],0
    for r in y:
        if r == 0:
            zero +=1
        else:
            if zero > 0:
                lst.append(zero)
                zero = 0
    try:
        return max(lst)
    except Exception as E:
        return 0

你们许多人不需要最后一部分而只返回max(lst)