有效地查找字符串中的重复字符

2024-05-12 22:26:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道这段代码的效率不是最优的(特别是在输入量巨大的情况下),而且我知道有一种方法可以改变此算法来处理其他数据类型,而不仅仅是字符串中的重复(显然只有这么多字符可供搜索)。

有什么办法可以提高效率吗?

我试着用字典,函数一直返回“none”,所以我试了一个列表,结果一切顺利。

提前感谢所有能帮我的人!

def find_repeater(string):
    my_list = []
    my_list.append(string[0])

    for i in range (1, len(string)):

        if string[i] in my_list:
            print 'repetition found'
            return (string[i])

        else:
            my_list.append(string[i])

print find_repeater('abca')  

现在有了字典….(它一直在控制台上打印“none”)

def find_repeater(string):
    my_dict = {}
    my_dict[0] = string[0]

    for i in range (1, len(string)):

        if string[i] in my_dict:
            print 'repetition found'
            return string[i]

        else:
            my_dict[i] = string[i]

print find_repeater('abca')  

Tags: innoneforstringlen字典mydef
3条回答

您可以使用collections查找重复字符:

import collections

freq = collections.Counter("abcda")
for k in freq:
    if freq[k] > 1:
        print k # prints "a"
        break

如果只想查找是否有重复(不查找重复字符):

letters = list("abcda")
no_rep = set(letters)
print len(letters) > len(no_rep) # prints 'True' when there are repeating characters

由于这是一个性能问题,让我们做一些计时:

def test_set(xs):
    seen = set()  # O(1) lookups
    for x in xs:
        if x not in seen:
            seen.add(x)
        else:
            return x

import collections

def test_counter(xs):
    freq = collections.Counter(xs)
    for k in freq:
        if freq[k] > 1:
            return k

def test_dict(xs):
    d = {}
    for x in xs:
        if x in d:
            return x
        d[x] = 1

def test_sort(xs):
    ys = sorted(xs)

    for n in range(1, len(xs)):
        if ys[n] == ys[n-1]:
            return ys[n]

##

import sys, timeit
print (sys.version + "\n")
xs = list(range(10000)) + [999]
fns = [p for name, p in globals().items() if name.startswith('test')]
for fn in fns:
    assert fn(xs) == 999
    print ('%50s %.5f' % (fn, timeit.timeit(lambda: fn(xs), number=100)))

我测试的是一个整数列表,而不是一个字符串(因为对于一个字符串,不能得到超过256个循环)。我机器上的结果是这样的:

3.2.3 (v3.2.3:3d0686d90f55, Apr 10 2012, 11:25:50) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]

                <function test_set at 0x1020f7380> 0.19265
               <function test_dict at 0x1020f7490> 0.12725
               <function test_sort at 0x1020f7518> 0.04683
            <function test_counter at 0x1020f7408> 0.92485

所以排序方法似乎是胜利者。我想这是因为它不会浪费时间创建散列和分配dict/set结构。另外,如果您不关心源列表的更改,您可以执行xs.sort(),而不是ys = sorted(xs),这样就没有内存占用。

另一方面,如果重复项更可能出现在输入的开头(如xs = 'abcdef' * 10000),那么set方法将执行得最好,因为它与sortCounter不同,一旦找到重复项,就立即返回,并且不需要预处理整个列表。如果您需要第一个重复元素,那么您还应该使用set,而不仅仅是其中一个。

Counter是一个很好的工具,但是它不是为性能而设计的,所以如果你真的需要处理“巨大的输入”,那么就使用集合(如果它们适合内存)或者合并排序(如果它们不适合内存)

def find_repeater(mystr):
    seen = set()  # O(1) lookups
    for char in mystr:
        if char not in seen:
            seen.add(char)
        else:
            print('repetition found')
            return char

相关问题 更多 >