使用Python异序词检测示例_清点法_排序法_蛮力法_计数法

要展示不同数量级的算法,一个好例子就是经典的异序词检测问题。如果一个字符串只是重排了另一个字符串的字符,那么这个字符串就是另一个的异序词,比如 heart 与 earth ,以及 python 与 typhon 。

为了简化问题,假设要检查的两个字符串长度相同,并且都是由26个英文字母的小写形式组成的。我们的目标是编写一个布尔函数,它接受两个字符串,并能判断它们是否为异序词。

1、方案1:清点法
def anagram_solution1(s1, s2):  # 清点法
    alist = list(s2)
    # 首先将s2存入alist列表,存这里的目的是为了
    # 核对一个核销一个(将对应的位置value设置为None)
    pos1 = 0
    stillOK = True

    while pos1 < len(s1) and stillOK:
        pos2 = 0
        found = False
        while pos2 < len(alist) and not found:
            # 取出s1中的字母和s2所保存的列表的
            if s1[pos1] == alist[pos2]:
                found = True
            else:
                pos2 += 1
        if found:
            alist[pos2] = None
            # 对符合条件的进行核销
        else:
            stillOK = False
        pos1 += 1
    return stillOK


print(anagram_solution1('heart', 'earth'))

通过分析可以给出公式: ∑ i = 0 n i = n ( n + 1 ) 2 = 1 2 n 2 + 1 2 n \sum_{i=0}^n i= \frac{n(n+1)}{2}=\frac{1}{2}n^2+\frac{1}{2}n i=0ni=2n(n+1)=21n2+21n
当n增大时,起决定性作用的是 n 2 n^2 n2,而 1 2 \frac{1}{2} 21可以忽略。故该方案的时间复杂度是 O ( n 2 ) O(n^2) O(n2)

2、方案2:排序法
def anagram_solution2(s1, s2):
    alist1 = list(s1)
    alist2 = list(s2)

    alist1.sort()
    alist2.sort()

    pos = 0
    matches = True
    while pos < len(s1) and matches:
        if alist1[pos] == alist2[pos]:
            pos += 1
        else:
            matches = False
    return matches


print(anagram_solution2('heart', 'earth'))

表面上来看该算法的复杂度似乎是 O ( n ) O(n) O(n),但由于调用了sort()进行排序,排序时复杂度基本上是 O ( n 2 ) O(n^2) O(n2) O ( n l o g n ) O(nlogn) O(nlogn),所以排序操作起主导作用。

3、蛮力法

用蛮力解决问题的方法基本上就是穷尽所有的可能。就异序词检测问题而言,可以用 s 1 s1 s1中的字符生成所有可能的字符串,看看 s 2 s2 s2是否在其中。但这个方法有个难处。显然暴力是时间复杂度最高的算法,很多时候并不是最优先考虑的方向。

4、计数法

计数法顾名思义就是建立一个容纳所有元素的容器,例如这里是26个字母,记录每个字母出现的次数,然后进行比对。
总步骤数: T ( n ) = 2 n + 26 T(n)=2n+26 T(n)=2n+26 即: O ( n ) O(n) O(n)

其中 ord() 函数作用是返回对应的 ASCII 数值,或者 Unicode 数值。

def anagram_solution4(s1, s2):
    c1 = [0] * 26
    c2 = [0] * 26
    for i in range(len(s1)):
        pos = ord(s1[i]) - ord('a')
        c1[pos] = c1[pos] + 1
    for i in range(len(s2)):
        pos = ord(s2[i]) - ord('a')
        c2[pos] = c2[pos] + 1
    j = 0
    stillOk = True
    while j < 26 and stillOk:
        if c1[j] == c2[j]:
            j += 1
        else:
            stillOk = False
    return stillOk
    
print(anagram_solution4('heart', 'earth'))

对上面方法进行封装

def anagram_solution4(s1, s2):
    c1 = count1(s1)
    c2 = count1(s2)
    j = 0
    stillOk = True
    while j < 26 and stillOk:
        if c1[j] == c2[j]:
            j += 1
        else:
            stillOk = False
    return stillOk


def count1(s):
    c = [0] * 26
    for i in range(len(s)):
        pos = ord(s[i]) - ord('a')
        c[pos] = c[pos] + 1
    return c

print(anagram_solution4('heart', 'earth'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值