关于算法:如何使用itertools模块在排序列表中获取下一个按字典顺序排列的字符串?

How to get the next lexicographically bigger string in a sorted list by using itertools module?

我需要输入一个字符串,并返回它的下一个字典中较大的字符串。例如,下一个字符串"anmdfg"是"anmdgf"。但是,输入的长度可能非常大,可能包含100个字符或更多,并且其中会有一些重复的字符。因此,我决定使用itertools.permutations,而不将其作为AVO的列表。内存消耗过度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python3
from itertools import permutations

a = list(input())
tuple_a = tuple(a)
b = permutations(a,len(a))
p = next(b)
result = ''

try:
    while 1:
        p = next(b)        
        if p > tuple_a:
            result = ''.join(p)
            print(result)
        break

except:
    if result == '':
        print('No answer.')
else:
    if result == '':
        print('No answer.')

我的示例中的b没有排序。似乎我必须首先生成列表。我尝试了,但它消耗了我的内存,以至于我没有时间终止进程。我有没有办法在不列清单的情况下对排列结果进行排序?


生成比输出少的所有排列确实非常低效。最好使用下面实现的经典线性时间算法:

1
2
3
4
5
6
def nextperm(lst):
  for i in range(len(lst) - 1, 0, -1):
    if lst[i-1] < lst[i]:
      for j in range(len(lst) - 1, i-1, -1):
        if lst[i-1] < lst[j]:
          return lst[:i-1] + lst[j:j+1] + lst[:j:-1] + lst[i-1:i] + lst[j-1:i-1:-1]


使用python生成下一个排列的实现相对简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    def nextperm(s):
        l=[]
       for i in range(len(s)):
        l.append(s[i])
       for i in range(-1,-len(s),-1):
         if (l[i] > l[i-1]):
           break
         else:
          pass
       pos=len(s)+(i-1)
      for i in range(pos,len(s),1):
           if (l[pos] > l[i]):
            (l[pos],l[i-1])=(l[i-1],l[pos])
              break
           else:
             pass
      l=l[:pos+1]+l[-1:-(len(s)-pos):-1]  
      s1=''.join(l)
      return(s1)


一般方法是:

  • 以列表形式查找字符串的所有排列。
  • 排序列表
  • 查找项目的索引
  • 然后拿旁边的东西
  • 以下是实现这一目标的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    >>> from itertools import permutations

    >>> my_string = 'anmdfg'

    # Permutation of all the strings
    >>> all_strings = list(permutations(my_string, len(my_string)))

    # Sorted lexicographically
    >>> all_string = sorted(all_strings)

    # index of current string
    >>> my_index = all_string.index(tuple(my_string))

    # Next item (but as tuple)
    >>> next_value = all_string[my_index+1]
    >>> next_value
    ('a', 'n', 'm', 'd', 'g', 'f')

    # Convert tuple to string
    >>> ''.join(next_value)
    'anmdgf'


    试试这个,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    def NextHighestWord(string):
        S = [ord(i) for i in string]
        #find non-incresing suffix from last
        i = len(S) - 1
        while i > 0 and S[i-1] >= S[i]:
            i = i - 1
        if i <= 0:
            return False

        #next element to highest is pivot
        j = len(S) - 1
        while S[j] <= S[i -1]:
            j = j - 1
        S[i-1],S[j] = S[j],S[i-1]

        #reverse the suffix
        S[i:] = S[len(S) - 1 : i-1 : -1]
        ans = [chr(i) for i in S]
        ans ="".join(ans)
        print(ans)
        return True

    test = int(input())
    for i in range(test):
        s = input()
        val = NextHighestWord(s)
        if val:
            continue
        else:
            print("no answer")

    我认为这样做的方法是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from itertools import dropwhile, permutations

    def next_largest(start):
       """Return the next largest permutation of the characters in start."""
        reference = tuple(start)
        try:
            return next(dropwhile(
                lambda p: p <= reference,
                permutations(sorted(start))
            ))
        except StopIteration:
            raise ValueError('No larger string available')

    请注意,在生成排列之前对start进行排序,以确保按词典编纂顺序生成排列。

    还要注意:

  • 我已经明确了我想要捕捉的错误,允许发生的任何意外错误正确传播(参见"EDOCX1的邪恶"(2));以及
  • 我使用的是next(thing),而不是thing.__next__()(参见python数据模型和内置函数之间的关系?).