繁体   English   中英

字符串操作算法查找大于原始字符串的字符串

[英]String manipulation algorithm to find string greater than original string

我有很少的单词(字符串),如'hefg','dhck','dkhc','lmno' ,它将通过交换部分或全部字符转换为新单词,使新单词大于原始单词的字典顺序新词也是比原词更重要的词。 例如'dhck'应该输出'dhkc'而不是'kdhc''dchk'或任何其他。

我有这些输入

hefg
dhck
dkhc
fedcbabcd

哪个应该输出

hegf
dhkc
hcdk
fedcbabdc

我在python中试过这个代码,除了'dkhc''fedcbabcd'之外,它适用于所有人。 我已经发现在'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))

你可以尝试这样的事情:

  • 以相反的顺序迭代字符串中的字符
  • 跟踪你已经看过的角色,以及你看到它们的位置
  • 如果你看到的字符比字符大,那就把它换成最小的字符
  • 对该位置后的所有字符进行排序以获得最小字符串

示例代码:

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

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

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

所以算法是:

  • 从字符串的后面开始(右端);
  • 在符号不断增加时向左走;
  • i成为s[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'

您的问题可以重新编写为查找字符串的下一个字典排列

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM