【问题标题】:Longest substring computational complexity最长子串计算复杂度
【发布时间】:2013-12-11 02:23:22
【问题描述】:

我想知道我的 MIT 在线 edx 课堂练习题的代码与提供的答案代码之间的区别。

课堂上的作业如下:

编写一个程序,打印 s 的最长子串,其中 字母按字母顺序出现。例如,如果 s = 'azcbobobegghakl',那么你的程序应该打印出来

按字母顺序排列的最长子串是:beggh

我们的自动化测试将为您提供 s 的值

我的成功代码:

curSlice='z'
for b in range(len(s)):
    for e in range(b+1,len(s)):
        if s[e-1]<=s[e]:
            if len(s[b:e+1])>len(aas):
                aas=s[b:e+1]
        else:
            break
print('Longest substring in alphabetical order is: '+str(aas))

逻辑是增加一个开始的字符串字母并测试每个后续字母的增加值,然后存储切片,如果大于当前切片,直到测试失败并且开始字母增加一。此时流程重新开始。

麻省理工学院的代码:

curString = s[0]
longest = s[0]
for i in range(1, len(s)):
    if s[i] >= curString[-1]:
        curString += s[i]
        if len(curString) > len(longest):
            longest = curString
    else:
        curString = s[i]
print 'Longest substring in alphabetical order is:', longest

哪个代码更高效?它们的长度大致相同,但我的有两个环。这是否使它没有优化?谢谢

【问题讨论】:

  • 两个嵌套循环几乎总是比一个循环慢得多,但您也可以在每个函数中抛出一个较大的输入来查看哪个更快。
  • 感谢您的编辑 Potatoswatter

标签: python for-loop time-complexity


【解决方案1】:

作为粗略的规则,添加更多循环会减慢速度。但这只是一个粗略的规则。看起来不像循环的东西在实际实现中可能是循环,从而减慢速度。例如,像curString += s[i] 这样看起来很无辜的代码实际上可能非常慢。那是因为,假设 curString 是一个 Python 字符串,你不能再多加一个字母。 Python 最终要做的是创建一个比旧字符串长 1 个字符的新字符串,然后将所有旧字符复制到新字符串中,然后附加一个新字符,然后将这个新字符串分配给 curString。两种实现都不是非常有效,因为它们都做这样的事情(使用 range 代替 xrange,复制字符串切片等)。但是,假设字符串相对较短,这也不太重要。

在任何情况下,您和他们的两种实现都可以固定,以便它们执行的每个操作都高效。在这种情况下,它确实会回到循环,并且它们的实现确实比你的更快。要了解原因,请考虑像“wxyabcd”这样的字符串。在考虑前三个字符(“w”、“x”和“y”)时,两种算法的作用几乎相同。但考虑一下接下来会发生什么。在您的代码中,您将遇到“a”,请注意这不是按字母顺序排列的,因此您结束了内部循环。您的外部循环将具有 b = 1,并且您将考虑以“x”开头的所有字符串。但是,这些不会给你一个比以“w”开头的字符串更长的字符串,所以这是浪费精力。在继续检查以“a”开头的字符串之前,您最终还是会检查“x”、“xy”和“y”,而 MIT 代码将直接跳转到以“a”开头的字符串。更具体地说,这是您的代码将考虑的字符串集:

w
wx
wxy
x
xy
y
a
ab
abc
abcd
b
bc
bcd
c
cd
d

这是 MIT 代码将考虑的内容

w
wx
wxy
a
ab
abc
abcd

如您所见,他们的代码做的工作少了很多。查看它的一种方法是,它们只“查看”字符串中的任何给定字符一次,而您将多次查看某些字符。

【讨论】:

    【解决方案2】:

    他们的答案代码更有效,因为它不会重复遍历子序列。给定子序列ABCDE,您的代码会在连续迭代中分别处理BCDECDEDE,即使它们不可能是最长的。

    因此,您的答案的最坏情况运行时间是 O(N^2) 与他们的 O(N)。是的,这与他们的答案中没有嵌套的 for 循环有关。

    【讨论】:

      【解决方案3】:

      或者,一次性完成并且没有字符串连接的开销:

      length, start, stop, i = len(s), 0, 0, 0
      
      while i < length:
      
          j = i+1
      
          while j < length and s[j] >= s[j-1]:
              j += 1
      
          if j - i > stop - start:
              start, stop = i, j
      
          i = j
      
      print(s[start:stop])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-16
        • 2013-05-28
        • 1970-01-01
        • 2011-02-12
        • 2016-12-05
        • 2017-11-04
        • 2012-12-31
        • 2019-03-11
        相关资源
        最近更新 更多