Python中的strcmp或如何高效排序子串(无复制)以构建后缀数组

10 投票
4 回答
10669 浏览
提问于 2025-04-15 19:24

这里有一个非常简单的方法,可以用Python从一个字符串构建一个后缀数组

def sort_offsets(a, b):
    return cmp(content[a:], content[b:])

content = "foobar baz foo"
suffix_array.sort(cmp=sort_offsets)
print suffix_array
[6, 10, 4, 8, 3, 7, 11, 0, 13, 2, 12, 1, 5, 9]

不过,"content[a:]" 这个写法会复制一份内容,当内容变得很大时,这样做就会变得非常低效。所以我在想有没有办法在不复制这两个子字符串的情况下进行比较。我试过使用内置的缓冲区,但没有成功。

4 个回答

3

这个问题真有意思,值得点赞!我找不到直接解决这个问题的明显方法,不过我用了一种新的比较方式,让处理速度大大提升(对于10万个字符的字符串,速度提升了十倍)。具体的比较函数是这样的:

def compare_offsets2(a, b):
    return (cmp(content[a:a+10], content[b:b+10]) or
            cmp(content[a:], content[b:]))

简单来说,就是先比较每个后缀的前10个字符;只有当这10个字符完全相同的时候,才继续比较整个后缀。

当然,10这个数字可以换成其他的,建议你试着找出最合适的值。

这个比较函数也很有意思,因为它不容易用其他的关键函数来替代。

5

我不知道有没有快速的方法来比较子字符串,但你可以通过使用 key 来让你的代码变得更快(也更简单),而不是用 cmp

suffix_array.sort(key=lambda a: content[a:])

这样做会让每个 a 的值只创建一次子字符串。

补充说明:一个可能的缺点是,这样会需要 O(n^2) 的内存来存储这些子字符串。

6

buffer这个函数并不是把整个字符串都复制一遍,而是创建了一个只指向原始字符串的对象。根据interjay的建议,可以这样做:

suffix_array.sort(key=lambda a: buffer(content, a))

撰写回答