当前位置: 首页 > 面试题库 >

字符串切片的时间复杂度

吕德业
2023-03-14
问题内容

切片Python字符串的时间复杂度是多少?鉴于Python字符串是不可变的,我可以想象对它们进行切片O(1)O(n)取决于切片的实现方式。

我需要编写一个遍历(可能很大)字符串的所有后缀的函数。我可以通过将后缀表示为整个字符串的元组和一个索引以开始从中读取字符来避免对字符串进行切片,但这很丑陋。相反,如果我天真地像这样写我的函数:

def do_something_on_all_suffixes(big_string):
    for i in range(len(big_string)):
        suffix = big_string[i:]
        some_constant_time_operation(suffix)

… …将其时间复杂度是O(n)或,其中是?O(n2)``n``len(big_string)


问题答案:

简短的答案:str通常是切片。这意味着对每个字符串n后缀进行切片的函数正在起作用。也就是说,如果可以使用s处理类似对象,则可以避免复制,以获取原始字节数据的零复制视图。有关
如何 使其工作的信息,请参见下面的如何进行 零拷贝切片
O(n2)``bytesmemoryview

长答案:(C)Pythonstr不会通过引用数据子集的视图进行切片。str切片共有三种操作模式:

  1. 完整切片,例如mystr[:]:返回完全相同的引用str(不只是共享数据,相同的实际对象,mystr is mystr[:]因为它str是不可变的,因此没有风险)
  2. 零长度切片和(取决于实现)缓存的长度1切片;空字符串是单例(mystr[1:1] is mystr[2:2] is ''),长度为1的低序数字符串也将被缓存为单例(在CPython 3.5.0上,看起来所有可在latin-1中表示的字符range(256)都被缓存了,即,是Unicode序数)。
  3. 所有其他切片:切片str在创建时复制,此后与原始副本无关str

#3之所以成为通用规则,是为了避免str因为只看到一小部分而将大量问题保留在内存中。如果您有一个1GB的文件,请按以下方式将其读入并切成薄片(是的,当您寻找时这很浪费,这只是为了说明):

with open(myfile) as f:
    data = f.read()[-1024:]

那么您将有1 GB的数据保留在内存中,以支持显示最后1
KB的视图,这是一个严重的浪费。由于切片通常很小,因此在切片上复制而不是创建视图几乎总是更快。这也意味着str可以更简单。它需要知道其大小,但也不必跟踪数据中的偏移量。

如何进行零拷贝切片

许多 方法可以在Python中执行基于视图的切片,而在Python 2中,它将可以使用str(因为str在Python
2中类似于字节,因此支持缓冲协议)。用的Py2str和PY3
bytes(以及许多其他数据类型,例如bytearrayarray.arraynumpy阵列,mmap.mmapS等),则可以创建一个memoryview,它是原始对象的零拷贝视图,并且可以在不复制数据切片。因此,如果您可以对Py2
str/ Py3使用(或编码)bytes,并且您的函数可以与任意类似bytes的对象一起使用,则可以执行以下操作:

def do_something_on_all_suffixes(big_string):
    # In Py3, may need to encode as latin-1 or the like
    remaining_suffix = memoryview(big_string)
    # Rather than explicit loop, just replace view with one shorter view
    # on each loop
    while remaining_suffix:  # Stop when we've sliced to empty view
        some_constant_time_operation(remaining_suffix)
        remaining_suffix = remaining_suffix[1:]

memoryviews切片确实创建了新的视图对象(它们只是超轻量的,固定大小与它们查看的数据量无关),只是没有任何数据,因此some_constant_time_operation可以存储副本,并且在需要时不会更改我们稍后将其切成薄片。如果您需要适当的副本作为Py2
str/ Py3
bytes,则可以调用.tobytes()获取原始bytesobj,或者(仅在Py3中显示),将其直接解码为str从缓冲区复制的a
,例如str(remaining_suffix[10:20], 'latin-1')



 类似资料:
  • 问题内容: 我有一个字符串,例如: 其中(逗号)将始终是最后一个字符的第三个字符,也就是。 我正在考虑删除’,’的方法,但只能考虑将字符串转换为列表,将其删除,然后将其转换回字符串。但是,对于简单任务而言,这似乎有点过多。 如何以更简单的方式完成此任务? 问题答案: 通常,您只需执行以下操作: 该给你一个字符串,最多,但不包括你要删除的逗号()和给你另一个字符串开始一个字符超出了逗号()。 然后,

  • 问题内容: 我想将字符串切片转换为指向字符串的指针切片 %!p(string = a)=>字符串 %!p(string = b)=>字符串 %!p(string = c)=>字符串 [0xc42000e1d0 0xc42000e1d0 0xc42000e1d0] 据我了解, 我的变量似乎是一个字符串,而不是指向字符串的指针。 因此应从迭代时复制。 显然我不正确,因为地址仍然相同。如果值不是指针,该

  • 问题内容: 在Java 6之前,我们在上有一个固定时间的子字符串。在Java 7中,为什么要使用复制数组并降级到线性时间复杂度? 问题答案: 在Oracle错误#4513622中讨论了为什么要做出决定:(str)保留字段的子字符串会阻止对象的GC: 如示例中那样调用String.substring时,未分配用于存储的新字符数组。它使用原始String的字符数组。因此,支持原始字符串的字符数组在子字

  • 在Swift中将字符串转换为数组的时间复杂度是多少,也就是:数组(“abc”)。是O(n)还是Swift使用某种类型的内部机制来优化它,因为String符合序列协议。

  • 问题内容: 我想通过实现以下目标: 我能够做到的唯一方法是: 现在,这个示例以及我真正拥有的是一个长长且混乱的字符串,因此我想将切片放入。我已经研究了docs,但无法找出正确的语法。我的问题是:是否可以在替换字段中切片字符串? 问题答案: 不可以,您无法将切片应用于替换字段中的字符串。 您需要参考Format Specification Mini- Language ;它定义了什么 是 可能的。这

  • 我遇到了单词中断问题,它是这样的: 给定一个输入字符串和一个字典,如果可能,将输入字符串分割成一个空间分隔的字典单词序列。 然而,在Quora中,一个用户发布了一个线性时间解决方案 我不知道它怎么会是线性的。他们在时间复杂度计算上有什么错误吗?这个问题的最佳可能最坏情况时间复杂度是多少。我在这里发布了最常见的DP解决方案