【问题标题】:How can I make this 2 strings matching algorithm more efficient?如何使这 2 个字符串匹配算法更有效?
【发布时间】:2020-12-03 14:40:53
【问题描述】:

所以我正在做这个关于代码大战的练习,我的代码做了它应该做的事情,但它需要更高效,我不知道我还能做什么。下面是我写的练习和代码。

完成函数 scramble(str1, str2),如果 str1 字符的一部分可以重新排列以匹配 str2,则返回 true,否则返回 false。

注意事项:

仅使用小写字母 (a-z)。不包含标点符号或数字。 性能需要考虑

Input strings s1 and s2 are null terminated.

例子

scramble('rkqodlw', 'world') ==> True
scramble('cedewaraaossoqqyt', 'codewars') ==> True
scramble('katas', 'steak') ==> False
def scramble(s1, s2):
    #initiate variables
    i,j,count =0,0,0
   #sorting our 2 strings
    s1, s2="".join(sorted(s1)),"".join(sorted(s2))
    #for loop to go over each character in the str we want to match, s2
    for j in range(len(s2)):
        
        #while loop to go over s1 to match characters to s2 char
        i=0
        while i<len(s1):
            #when 2 chars match, count increases by 1, i increases to exit while loop
            #s1 sliced for increasing efficiency in the next loop
            if s1[i]==s2[j]:
                count+=1
                x=i 
                i=len(s1)
                s1=s1[x+1:]
            
            #if character larger in s1, no need to go through the whole string
            #therefore, exits while loop and slices
            elif s1[i]>s2[j]:
                x=i 
                i=len(s1)
                s1=s1[x+1:]
            
            #increases iterator
            else: i+=1
    
    #return statement, if count equals length of s2 then it must be true
    if len(s2)==count: return True
    else: return False

附带问题:这段代码的时间复杂度是 O(n^2) 吗?

【问题讨论】:

  • 你应该在代码审查上发布这个。 SO 侧重于尚未运行的代码/程序,而代码审查侧重于代码优化。
  • 有什么理由不能只使用哈希图并比较 s1 和 s2 中字母的频率吗?基本上,问题是“我可以使用 s1 中的字母构造 s2 吗?”。如果 s2 中的所有字母都在 s1 中,您可以这样做,对吗?那么你可以为 s2 创建一个字母的频率图并与 s1 的频率图进行比较吗?
  • 还有一些计数器可以应用于字符串来计算一个字符在字符串中出现的频率。对于这种情况,它可能会更有效率。看看 collections.counter
  • @JeremyFisher 更好的是,您只需要通过 s1 来获取计数,然后通过 s2 来减少它们。如果你在 s2 中找到一个不在 s1 中的字符,或者得到一个低于 0 的计数,那么答案是否定的。否则是的。
  • @btilly 是的,我认为这也可以。肯定更聪明更节省空间。

标签: python algorithm sorting matching


【解决方案1】:

如果你试图从一个不存在的列表中查找并弹出一个元素,你可以利用抛出异常的事实:

def scramble(s1,s2):
    l1 = list(s1)
    for c in s2:
        try:
            i = l1.index(c)
            l1.pop(i)
        except:
            return False
    return True

【讨论】:

    【解决方案2】:

    所以在这里你正在对两个字符串进行排序,这使得 O(n log n + m log m) 复杂性 nm 是大小s1s2。然后,您将运行两个嵌套循环来检查 s2 中的字符是否存在于 s1 中,然后如果有问题的字符确实存在,则重写 s1。这实际上是非常低效的,并且它确实为您提供了 O(nm) 复杂性,顶部有一个相当大的常量(因为您一遍又一遍地重写字符串)。

    相反,您可以只计算每个字符串中每个字符的出现次数,看看您是否有足够的字符来从s1 组成s2。这将为您提供线性时间加上字母的大小,这是一个小常数(在您的情况下为 26,因为根据挑战提示只允许使用小写字母字符)。

    【讨论】:

    • 由于这是你正在做的编码挑战,我将把实现留给你 :) 如果你有任何问题,请告诉我!
    • 感谢您的解释!你帮我把我的代码减少到只有 4 行! def scramble(s1, s2): for char in s2: if s1.count(char)&lt;s2.count(char):return False return True 但是,.count 的时间复杂度为 O(n),这仍然使其效率低下。你有什么建议吗?
    • 当然!有两种方法可以改进它: 1. 最简单但仍然相当低效:如果你可以循环 'a' 到 'z' (总是 26),为什么还要循环 s2 中的所有字符(可能很大)?它将给出 (26 * (len(s1)+len(s2))) 次迭代 2。不太容易,但效率最佳:从 char 程序上创建一个到出现次数的 dict:将所有初始化为 0,然后循环遍历字符串一次,每次迭代增加适当的单元格。对两个字符串都这样做。最后,遍历字母表并检查值是否正确对齐。这只是 (26 + len(s1)+len(s2)) 迭代!享受吧!
    猜你喜欢
    • 2014-03-17
    • 1970-01-01
    • 1970-01-01
    • 2011-09-04
    • 1970-01-01
    • 2015-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多