字符串处理算法查找比原始字符串大的字符串

时间:2019-02-15 13:36:43

标签: python string algorithm

我很少有像'hefg','dhck','dkhc','lmno'这样的单词(字符串),可以通过交换一些或所有字符来转换成新单词,以使新单词在字典上大于原始单词,而且新单词最少大于原始单词的所有单词。 例如'dhck' 应该输出'dhkc'而不是'kdhc''dchk'或其他任何值。

我有这些输入

hefg
dhck
dkhc
fedcbabcd

应输出

hegf
dhkc
hcdk
fedcbabdc

我已经尝试在python中使用此代码,该代码可用于'dkhc''fedcbabcd'以外的所有代码。 我发现'fedcbabcd'的第一个字符是最大值,因此不会被交换。 我正在"ValueError: min() arg is an empty sequence"

如何修改算法以解决问题?

list1=['d','k','h','c']
list2=[]
maxVal=list1.index(max(list1))
for i in range(maxVal):
    temp=list1[maxVal]
    list1[maxVal]=list1[i-1]
    list1[i-1]=temp
    list2.append(''.join(list1))
print(min(list2))

3 个答案:

答案 0 :(得分:2)

您可以尝试以下操作:

  • 以相反的顺序迭代字符串中的字符
  • 跟踪您已经看过的字符以及在哪里看到它们
  • 如果您看到的字符大于当前字符,请将其替换为最小的较大字符
  • 对该位置之后的所有字符进行排序,以获取最小的字符串

示例代码:

def next_word(word):
    word = list(word)
    seen = {}
    for i in range(len(word)-1, -1, -1):
        if any(x > word[i] for x in seen):
            x = min(x for x in seen if x > word[i])
            word[i], word[seen[x]] = word[seen[x]], word[i]
            return ''.join(word[:i+1] + sorted(word[i+1:]))
        if word[i] not in seen:
            seen[word[i]] = i

for word in ["hefg", "dhck", "dkhc", "fedcbabcd"]:
    print(word, next_word(word))

结果:

hefg hegf
dhck dhkc
dkhc hcdk
fedcbabcd fedcbabdc

答案 1 :(得分:2)

在一般情况下,最大字符及其位置不影响算法。例如,对于'fedcbabcd',您可以在字符串的开头加上az,这不会改变您需要交换最后两个字母的事实。

考虑输入'dgfecba'。在这里,输出为'eabcdfg'。为什么?请注意,最后六个字母是按降序排列的,因此,通过在此处更改任何内容,您将在字典上得到一个较小的字符串,这是不好的。因此,您需要替换初始的'd'。我们应该把它放在什么位置?我们想要比'd'大的东西,但要尽可能小,所以'e'。剩下的六个字母呢?同样,我们想要一个尽可能小的字符串,所以我们按字母顺序对字母进行排序:'eabcdfg'

所以算法是:

  • 从字符串的末尾开始(右端);
  • 在符号不断增加的同时向左走;
  • is[i] < s[i + 1]的最右边;在我们的例子中,i = 0;
  • 保留位置0、1,...,i上的符号-1保持不变;
  • i+1 ... n-1中找出包含大于s[i]的最小符号的位置;将此职位称为j;在我们的例子中,j = 3;
  • 交换s[i]s[j];在我们的情况下,我们获得'egfdcba';
  • 反转字符串s[i+1] ... s[n-1];在我们的情况下,我们获得'eabcdfg'

答案 2 :(得分:0)

您的问题可以改写为finding the next lexicographical permutation of a string

上面链接中的算法描述如下:

  

1)找到最长的不增加后缀

     

2)左边的数字   后缀是我们的关键

     

3)在中找到枢轴的最右后继   后缀

     

4)交换后继者和支点

     

5)反转后缀

上述算法特别有趣,因为它是 O(n)

代码

def next_lexicographical(word):
    word = list(word)

    # Find the pivot and the successor
    pivot = next(i for i in range(len(word) - 2, -1, -1) if word[i] < word[i+1])
    successor = next(i for i in range(len(word) - 1, pivot, -1) if word[i] > word[pivot])

    # Swap the pivot and the successor
    word[pivot], word[successor] = word[successor], word[pivot]

    # Reverse the suffix
    word[pivot+1:] = word[-1:pivot:-1]

    # Reform the word and return it
    return ''.join(word)

如果单词已经是最后的字典排列,则上述算法将引发StopIteration异常。

示例

words = [
    'hefg',
    'dhck',
    'dkhc',
    'fedcbabcd'
]

for word in words:
    print(next_lexicographical(word))

输出

hegf
dhkc
hcdk
fedcbabdc