【问题标题】:Longest sequence of consecutive letters最长连续字母序列
【发布时间】:2017-06-04 15:48:04
【问题描述】:

假设我有一串小写字母,例如

'ablccmdnneofffpg'

我的目标是在这个字符串中找到最长的连续数字序列,在这种情况下是:

'abcdefg'

直观的尝试是在每个字母周围找到循环并获得从该字母开始的最长序列。一种可能的解决方案是

longest_length = 0
start = None
current_start = 0
while current_start < len(word) - longest_length:
    current_length = 1
    last_in_sequence = ord(word[current_start])
    for i in range(current_start + 1, len(word)):
        if ord(word[i]) - last_in_sequence == 1:
            current_length += 1
            last_in_sequence = ord(word[i])
    if current_length > longest_length:
        longest_length = current_length
        start = current_start
    while (current_start < len(word) - 1 and
           ord(word[current_start + 1]) - ord(word[current_start]) == 1):
        current_start += 1
    current_start += 1

有没有其他方法可以用更少的行来解决问题,甚至使用一些pythonic方法?

【问题讨论】:

  • 你想找到最长的序列,还是这样的序列的长度
  • 您的算法使用 CPU 周期。您可以一次跟踪所有可能的序列,然后只迭代一次以换取内存。

标签: python sequence


【解决方案1】:

您可以使用字典跟踪字符串中连续字符的所有子序列,然后获取长度最大的子序列。

每个子序列由字母表中的下一个候选者键入,因此一旦在字符串中到达预期的候选者,它就会用于更新字典中相应子序列的值并添加为由下一个字母键入的新字典值:

def longest_sequence(s):
    d = {}
    for x in s:
       if x in d:
           d[chr(ord(x)+1)] = d[x] + x
       else:
           d[chr(ord(x)+1)] = x
    return max(d.values(), key=len)

print(longest_sequence('ablccmdnneofffpg'))
# abcdefg
print(longest_sequence('ba'))
# b
print(longest_sequence('sblccmtdnneofffpgtuyvgmmwwwtxjyuuz'))
# stuvwxyz

【讨论】:

  • @DSM 已更新。在"ba" (给出'b''a';可以使用OrderedDict 固定排序)和许多其他对象上进行测试。
  • 很好的解决方案,当我看到问题时采取了相同的方法。 max(v for v in d.values())max(d.values()) 相同,顺便说一句。
  • @schwobaseggl 我认为不一样。 max(d.values()) 检查max 每个字符,而不是长度。
  • @schwobaseggl 哈哈,谢谢。我已经修改了一个嵌套表达式来实现这一点。 现在嘲笑自己
  • 非常感谢@MosesKoledoye,你的方法很简洁,很好理解。
【解决方案2】:

一种用(一些)时间交换内存的解决方案:

它会跟踪所有看到的序列,然后在最后打印找到的最长的序列(尽管可能不止一个)。

from contextlib import suppress


class Sequence:
    def __init__(self, letters=''):
        self.letters = letters
        self.last = self._next_letter(letters[-1:])

    def append(self, letter):
        self.letters += letter
        self.last = self._next_letter(letter)

    def _next_letter(self, letter):
        with suppress(TypeError):
            return chr(ord(letter) + 1)
        return 'a'

    def __repr__(self):
        return 'Sequence({}, {})'.format(repr(self.letters),
                                         repr(self.last))


word = 'ablccmdnneofffpg'
sequences = []
for letter in word:
    for s in sequences:
        if s.last == letter:
            s.append(letter)
            break
    else:
        sequences.append(Sequence(letters=letter))

sequences = list(sorted(sequences, key=lambda s: len(s.letters), reverse=True))
print(sequences[0].letters)

【讨论】:

    【解决方案3】:

    您基本上要求longest increasing subsequence,这是一个经过充分研究的问题。看看维基百科中的pseudo code

    【讨论】:

    • 不完全。 abfh 是一个递增子序列,但不满足 OP 的条件,即它必须由 连续 个字母组成。另一方面,它显然与longest increasing subsequence问题有关,可以针对这个问题调整相应的算法。
    【解决方案4】:

    类似于MosesKoledoye's 解决方案,但仅存储字符序数的长度,并且仅在最后构建解决方案字符串。因此,这应该更节省空间:

    def longest_seq(s):
      d = {}
      for c in s:
        c, prev_c = ord(c), ord(c) - 1
        d[c] = max(d.get(c, 0), d.pop(prev_c, 0) + 1)
      c, l = max(d.items(), key=lambda i: i[1])
      return ''.join(map(chr, range(c-l+1, c+1)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-19
      • 1970-01-01
      • 1970-01-01
      • 2012-12-11
      相关资源
      最近更新 更多