【问题标题】:Longest alphabetical substring - where to begin最长的字母子串 - 从哪里开始
【发布时间】:2018-05-16 08:57:59
【问题描述】:

我正在研究流行的 MIT 课程中的“最长字母子串”问题。我已经阅读了很多关于如何编码的信息,但我真的很难在概念上实现飞跃。之前的手指练习并不太难。我想知道是否有人知道那里有任何材料可以真正打破在这个问题中使用的解决问题的方法。我试过拿出笔和纸,但我迷路了。我看到人们使用各种“计数器”或包含“迄今为止最长的子字符串”的字符串,当我查看其他人的解决方案时,我可以理解他们对他们的代码做了什么,但如果我试图合成我自己的东西,只是没有点击。

我什至从课程中休息并尝试通过其他一些书籍学习,但我不断回到这个问题并觉得我需要突破它。我想我正在努力实现从了解一些 Python 语法和工具到实际有机地使用这些工具来解决问题或“计算”的飞跃。

在有人指出我之前,我知道旨在提供帮助的课程材料。我看过其中一位助教制作的一些视频,这些视频有些帮助,但他并没有真正分解这一点。我觉得我需要与某人或类似的人配对编程...

供参考,问题如下:

假设 s 是一串小写字符。

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

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

在平局的情况下,打印第一个子字符串。例如,如果 s = 'abcbcd',那么你的程序应该打印

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

我知道发布代码很有帮助,但我没有任何其他地方没有的东西,因为,嗯,这就是我在 IDE 中一直在玩的东西,看看我是否能理解发生了什么。同样,不要寻找代码 sn-ps - 更多的阅读或资源将扩展此问题中使用的逻辑。我会发布我所拥有的,但它并不完整,而且在我开始感到困惑之前,我已经做到了。

s = 'azcbobobegghakl'

current = s[0]
longest = s[0]

for letter in range(0, len(s) -1):
    if s[letter + 1] >= s[letter]:
        current.append(s[letter + 1])
        if len(current) > len(longest):
            longest = current
        else:
            current = 

抱歉,格式错误,这仍然是新的。我对这个问题感到非常沮丧。

【问题讨论】:

  • @ScipioneSarlo 他有,看看底部
  • 我建议首先尝试实现一个更简单、更慢的算法来完成工作。您正在寻找一个按字母顺序排列的子字符串,嗯,它必须从某个地方开始,并且必须在它开始后的某个地方结束——因此可行的方法是尝试所有可能的子字符串,并测试它是否是按字母顺序排列的;如果是这样,还要检查它是否比你迄今为止看到的最长的更长;如果它通过了这两项测试,则使其成为当前的“冠军”。如果现在这看起来太难了,我建议一个更简单的问题:在数字列表中找到最大数字。

标签: python algorithm sorting


【解决方案1】:

在你的例子中你几乎就在那里,只需要稍微调整一下

s = 'azcbobobegghakl'

longest = [s[0],]  # make them lists so we can manipulate them (unlike strings)
current = [s[0],]

for letter in range(0, len(s) -1):
    if s[letter + 1] >= s[letter]:
        current.append(s[letter + 1])
        if len(current) > len(longest):
            longest = current
    else:
        current = [s[letter+1],]  # reset current if we break an alphabetical chain

longest_string = ''.join(longest)  # turn out list back into a string

longest_string的输出:

'beegh'

【讨论】:

  • 对于“ihabtylmnrpqrs”的输出应该是“pqrs”,但它给出的是“abty”
  • @ashishpal 我的意思是,这些结果都不是错误的。这取决于您是否希望第一个或最后一个遇到的等长最长。将> 更改为>= 将解决该问题。
  • 感谢您抽出宝贵时间回复,但我想我正在努力解决的问题更多的是概念......我想我显然也在努力处理代码,但我希望更多一些阅读材料或类似材料,以帮助使概念坚持下去。我什至不知道正确的词来询问正在使用的概念。都一样,谢谢
  • 嗯,这不是真正的堆栈溢出的地方。 reddit.com/r/learnpython 可能对你更有用
【解决方案2】:

如果您正在为解决这个问题背后的概念和逻辑而苦苦挣扎,我建议您稍微退后一步,并通过更简单的编码教程和交互式练习。您可能还喜欢尝试使用 JavaScript,从一开始就更容易获得创意,构建可以立即在浏览器中交互的 sn-ps 和/或网页。然后,当您掌握更多有趣的编码词汇时,其中的算法部分会显得更加熟悉和自然。我也认为让你自己的创造力和想象力引导你可以成为一个非常强大的学习过程。

让我们暂时忘记字母部分。想象一下,我们有一袋字母,我们一次取出一个,却不知道下一个是哪个,我们必须连续记录最长的Rs。你会怎么做?让我们试着用文字来描述这个过程,然后用伪代码来描述。

我们将保留一个容器用于迄今为止我们见过的最长运行,另一个用于检查当前运行。我们拉字母直到我们连续击中两个Rs,我们把它放在“当前”容器中。下一个字母不是R,这意味着我们的运行结束。 “迄今为止最长”的运行是空的,所以我们将“当前”容器倒入其中并继续。接下来的四个字母不是Rs,所以我们忽略它们。然后我们得到一个R,我们把它放入“当前”,然后是一个H。我们的运行再次结束,但这次我们在“当前”中的R 少于我们在“迄今为止最长”中已经拥有的两个,因此我们保留它们并为空“当前”。

我们得到一个A、一个B和一个C,然后运行五个Rs,我们将它们一个一个放入“当前”容器中。我们的包现在包含最后一个字母,T。我们看到我们的运行再次结束,并且“当前”容器比“迄今为止最长”的容器更多,所以我们倒出“最长”并将其内容替换为“当前”中的五个 Rs。就是这样,我们在包里找到了最长的Rs。 (如果我们有更多的运行,每次结束时我们都会选择是否替换“longest-so-far”的内容。)

在伪代码中:

// Initialise
current <- nothing
longest <- nothing

for letter in bag:
  if letter == 'R':
    add 'R' to current
  else:
    if there are more letters
    in current than longest:
      empty longest and pour
      in letters from current
    otherwise:
      empty current to get ready
      for the next possible run

现在,按字母顺序排列的规定只是稍微复杂化了我们的情况。我们将需要跟踪放置在“当前”中的最新字母,并且为了继续运行,它不会看到另一个重要的相同字母。相反,下一个字母必须比我们放在 current 中的最后一个字母“更大”(按字典顺序);否则运行结束,我们会根据“longest-so-far”执行我们的数量检查。

【讨论】:

  • 感谢您抽出宝贵的时间来写这篇文章。我想我在我的伪代码中一直在做的一件不太有效的事情是由于某种原因试图避免抽象——我认为你展示的真正只关注手头概念的方法是有帮助的。我还在解决这个问题,很快就会报告。
  • 我忘了跟进,但这种思路确实帮我解决了这个问题。在回到这个问题之前,我花了一些时间远离它,只是对循环更加熟悉。您的伪代码真的很有帮助,我想再次感谢您抽出时间帮助我!
【解决方案3】:

通常,从输入创建所有可能性的列表,然后根据所需的附加逻辑过滤结果更容易。例如,查找最长子串时,可以找到输入的所有子串,然后只保留有效序列的元素:

def is_valid(d):
  return all(d[i] <= d[i+1] for i in range(len(d)-1))

def longest_substring(s):
  substrings = list(filter(is_valid, [s[i:b] for i in range(len(s)) for b in range(len(s))]))
  max_length = len(max(substrings, key=len)) #this finds the length length of the longest valid substring, to be used if a tie is discovered
  return [i for i in substrings if len(i) == max_length][0]

l = [['abcbcd', 'abc'], ['azcbobobegghakl', 'beggh']]
for a, b in l:
  assert longest_substring(a) == b

print('all tests passed')

输出:

all tests passed

【讨论】:

    【解决方案4】:

    对我来说,处理实现复杂性的一种方法是编写一些单元测试:在某些时候,如果我无法从“阅读代码”中找出问题所在,和/或缺少哪些部分,我喜欢编写单元测试,这是解决问题的一种“正交”方法(而不是思考“我该如何解决这个问题?”我问自己“我应该编写什么测试来验证它是否正常工作?”)。

    然后,通过运行测试,我可以观察实现的行为方式,并尝试“一个一个”地解决问题,即专注于使下一个单元测试通过。

    这也是一种“将大问题化为更容易推理的小问题”的方法。

    【讨论】:

      【解决方案5】:
      s = 'azcbobobeggh'
      
      ls = [] #create a new empty list
      
      for i in range(len(s) - 1): # iterate s from index 0 to index -2
          if s[i] <= s[i+1]: # compare the letters
              ls.append(s[i]) # after comparing them, append them to the new list
          else:
              ls.append(s[i])
              ls.append('mark') # place a 'mark' to separate them into chunks by order
      ls.append(s[-1]) # get back the index -1 that missed by the loop
      
      # at this point here ls:
      # ['a', 'z', 'mark', 'c', 'mark', 'b', 'o', 'mark', 'b', 'o', 'mark', 'b', 'e', 'g', 'g', 'h']
      
      ls = str(''.join(ls)) # 'azmarkcmarkbomarkbomarkbeggh'
      ls = ls.split('mark') # ['az', 'c', 'bo', 'bo', 'beggh']
      res = max(ls, key=len) # now just find the longest string in the list
      
      print('Longest substring in alphabetical order is: ' + res)
      
      # Longest substring in alphabetical order is: beggh
      

      【讨论】:

      • 请解释你的答案,不要只发布代码块。
      • @dorukerenaktas 感谢您的评论。我已经编辑了我的答案。
      猜你喜欢
      • 1970-01-01
      • 2012-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多