3 回答
TA贡献1848条经验 获得超6个赞
你可以尝试这样的事情:
以相反的顺序迭代字符串中的字符
跟踪你已经看过的角色,以及你在哪里看到他们
如果您看到比当前字符大的字符,请将其与最小的较大字符交换
对该位置之后的所有字符进行排序以获得最小字符串
示例代码:
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
TA贡献1784条经验 获得超9个赞
在一般情况下,最大字符及其位置不会影响算法。例如,对于'fedcbabcd'
,您可以在字符串的开头添加ana
或 az
并且不会改变您需要交换最后两个字母的事实。
考虑输入'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'
。
TA贡献1803条经验 获得超6个赞
我们可以将您的问题改写为查找 string 的下一个字典排列。
上述链接中的算法描述如下:
1) 找出最长的非递增后缀
2)后缀左边的数字是我们的支点
3)在后缀中找到pivot最右边的后继
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
添加回答
举报