如何在Python中优化str.replace()

时间:2019-05-11 11:45:21

标签: python optimization bit-manipulation

我正在处理二进制字符串(即它仅包含1和0),并且我需要运行N次函数。此函数将字符串中的“ 01”的任何实例替换为“ 10”。但是,str.replace需要花费太多时间来处理输出,特别是当字符串的长度以及N的长度可以达到10 ^ 6时。

我尝试实现正则表达式,但是它没有为我提供任何优化,而是花了更多时间来执行任务。

例如,如果提供给我的字符串为01011并且N等于1,则输出应为10101。类似地,如果N变为2,则输出为11010,依此类推。

在python中是否有对str.replace的优化,或者我可以做些什么操作来优化代码?

3 个答案:

答案 0 :(得分:3)

让我们把输入想像成一个无符号整数,可能是一个很大的整数。例如:

  1001 1011  # input number X
  0100 1101  # Y = X>>1 = X//2 -- to get the previous bit to the same column
  1001 0010  # Z1 = X & ~Y -- We are looking for 01, i.e. 1 after previous 0
  0001 0010  # Z2 = Z1 with the highest bit cleared, because we don't want
             # to process the implicit 0 before the number
  1010 1101  # output = X + Z2, this adds 1 where 01's are;
             # 1 + 01 = 10, this is what we want

因此,我们只需很少的算术运算就可以处理整个列表。


更新:示例代码,我试图解决有关前导零的注释。

xstr = input("Enter binary number: ")
x = int(xstr, base=2)
digits = len(xstr)
mask = 2**(digits-1) - 1 
print("{:0{width}b}".format(x,width=digits))

while True:
    z2 = x & ~(x >> 1) & mask
    if z2 == 0:
        print("final state")
        break
    x += z2
    print("{:0{width}b}".format(x,width=digits))

答案 1 :(得分:2)

虽然这不是实际替换问题的答案,但我的初步调查表明,翻转规则最终会将所有1排在字符串的开头,将所有0排在结尾,因此以下函数将给出如果N接近len(s),则正确答案。

from collections import Counter

def asymptote(s, N):
    counts = Counter(s)
    return '1'*counts['1'] + '0'*counts['0']

我将结果与

def brute(s, N):
    for i in range(N):
        s = s.replace('01', '10')
    return s

此图显示了在蛮力法和随机字符串的渐近结果之间有何一致之处

Asymptotic result compared

黄色部分是蛮力和渐近结果相同的地方。这样一来,您通常至少需要进行len(s)/2次翻转才能获得渐近结果,有时甚至还需要更多一些(红线是3 * len(s)/ 4)。

答案 2 :(得分:0)

这是我谈到的程序:

from typing import Dict

from itertools import product

table_1 = {
    "01": 1,
    "11": 0,
}

tables = {
    1: table_1
}


def _apply_table(s: str, n: int, table: Dict[str, int]) -> str:
    tl = n * 2
    out = ["0"] * len(s)
    for i in range(len(s)):
        if s[i] == '1':
            if i < tl:
                t = '1' * (tl - i - 1) + s[:i + 1]
            else:
                t = s[i - tl + 1:i + 1]
            o = table[t]
            out[i - o] = '1'
    return ''.join(out)


def _get_table(n: int) -> Dict[str, int]:
    if n not in tables:
        tables[n] = _generate_table(n)
    return tables[n]


def _generate_table(n: int) -> Dict[str, int]:
    def apply(t: str):
        return _apply_table(_apply_table(t, n - 1, _get_table(n - 1)), 1, table_1)

    tl = n * 2
    ts = (''.join(ps) + '1' for ps in product('01', repeat=tl - 1))
    return {t: len(apply(t).rpartition('1')[2]) for t in ts}


def transform(s: str, n: int):
    return _apply_table(s, n, _get_table(n))

这不是很快,但是transform的时间复杂度为O(M),其中M是字符串的长度。但是_generate_table函数的空间复杂度和不良的时间复杂度使其无法使用:-/(但是,您可以对其进行改进,或者以更快的速度在C中实现它。(它也会变得更好。如果您存储哈希表而不是每次都不重新计算)