Python算法分析——以异序词检测为例

本文介绍了Python中解决异序词检测问题的三种算法:清点法、排序法和计数法。清点法通过替换字符实现,时间复杂度为O(n^2);排序法利用字符串排序,时间复杂度取决于排序算法,通常是O(n log n);而计数法通过统计字符出现次数,时间复杂度为O(n)。这些方法在空间和时间效率上有所不同,适用于不同场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python算法分析——以异序词检测为例

异序词算法分析

要展示不同数量级的算法,一个好例子就是经典的异序词检测问题。

如果一个字符串只是重排了另一个字符串的字符,那么这个字符串就是另一个的异序词,比如heart与earth,以及python与typhon。为了简化问题,假设要检查的两个字符串长度相同,并且都是由 26 26 26个英文字母的小写形式组成的。我们的目标是编写一个布尔函数,它接受两个字符串,并能判断它们是否为异序词。

1. 清点法

清点第 1 1 1个字符串的每个字符,看看它们是否都出现在第 2 2 2个字符串中。如果是,那么两个字符串必然是异序词。清点是通过用Python中的特殊值 N o n e None None 取代字符来实现的。但是,因为Python中的字符串是不可修改的,所以先要将第 2 2 2个字符串转换成列表。在字符列表中检查第1个字符串中的每个字符,如果找到了,就替换掉。

def anagramSolution1(s1, s2):
    alist = list(s2)
    pos1 = 0
    stillOK = True

    while pos1 < len(s1) and stillOK:
        pos2 = 0
        found = false
        while pos2 < len(s2) and not found:
            if s1[pos1] == alist[pos2]:
                found = True
            else:
                pos2 = pos2 + 1
         
        if found:
            alist[pos2] = None
        else:
            stillOK = False

        pos1 = pos1 + 1

    return stillOK

在该算法中,对于s1中的 n n n个字符,检查每一个时都要遍历s2中的 n n n个字符。要匹配s1中的一个字符,列表中的 n n n个位置都要被访问一次。因此,访问次数就成了从 1 1 1 n n n的整数之和。这可以用以下公式来表示。
∑ i = 1 n i = n ( n + 1 ) 2 = 1 2 n 2 + 1 2 n \sum_{i=1}^{n}i=\frac{n(n+1)}{2}=\frac{1}{2}n^2+\frac{1}{2}n i=1ni=2n(n+1)=21n2+21n
这个方案的时间复杂度是 O ( n 2 ) O(n^2) O(n2)

2. 排序法

尽管s1与s2是不同的字符串,但只要由相同的字符构成,它们就是异序词。基于这一点,可以采用另一个方案。如果按照字母表顺序给字符排序,异序词得到的结果将是同一个字符串。

在Python中,可以先将字符串转换为列表,然后使用内建的sort()方法对列表排序。

def anagramSolution2(s1, s2):
    alist1 = s1
    alist2 = s2

    alist1.sort()
    alist2.sort()

    pos = 0
    matches = True

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

该算法中, s o r t ( ) sort() sort()排序的时间复杂度即为排序算法的时间复杂度,基本上为 O ( n 2 ) O(n^2) O(n2)或者 O ( n ∗ l n ( n ) ) O(n*ln(n)) O(nln(n)),排序后遍历一次比较 n n n个字符时间复杂度为 O ( n ) O(n) O(n),故总时间复杂度主要取决于sort()函数所采用的排序算法。

3. 穷举法

可以用s1中的字符生成所有可能的字符串,看看s2是否在其中。

时间复杂度为 O ( n ! ) O(n!) O(n!),算法效果过差,故不再提供代码示例。

4. 计数法

该算法基于以下事实:
两个异序词有同样数目的 a a a、同样数目的 b b b、同样数目的 c c c,等等。

要判断两个字符串是否为异序词,先数一下每个字符出现的次数。因为字符可能有 26 26 26种,所以使用 26 26 26个计数器,对应每个字符。每遇到一个字符,就将对应的计数器加 1 1 1。最后,如果两个计数器列表相同,那么两个字符串肯定是异序词。

def anagramSolution4(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 = j + 1
        else:
            stillOK = False
        
    return stillOK

前两个计数循环都是 n n n阶的。第 3 3 3个循环比较两个列表,由于可能有 26 26 26种字符,因此会循环 26 26 26次。全部加起来,得到总步骤数 T ( n ) = 2 n + 26 T(n)=2n+26 T(n)=2n+26 ,即时间复杂度为 O ( n ) O(n) O(n)

但是,该算法要用额外的空间来存储寄存器,即用空间换时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值