
如果您简短地描述什么是字典顺序,这是按字母顺序排序的。 即 字符序列-AAA→AAB→AAC→AAD→………→WWW-按字母顺序(或本词典顺序)排序。
假设您有一个有限的字符序列,例如0、1、2、5、3、3、0,并且需要查找这些字符的所有可能排列。 最直观,也是最困难的是递归算法,当我们从序列中选择第一个字符,然后递归选择第二,第三个等时,直到选择了序列中的所有字符。 显然,这种算法的复杂度为O(n!)。
但是事实证明,按字典顺序生成所有排列的最简单算法是从最小的顺序开始,然后重复计算就位的下一个排列。 让我们来看看如何做。
正如计算下一个整数值一样,我们应该尝试增加序列的右侧,而左侧保持不变。
以上面的序列为例-(0,1,2,5,5,3,3,0)。 要使序列比原始序列高,只需在位置上重新排列第一个和第二个元素就足够了,但这不是必需的,因为您可以重新排列第二个和第三个元素并获得一个升序更近的序列。 这将导致我们进入下一个更紧密的排列,等等。
在这种情况下,最佳算法如下:
- 首先,您需要找到最大的不增加后缀。 在上面的示例中,这将是-(5,3,3,0)。 如果您尝试按此顺序进行任何排列,那么它将不会高于原始排列。
值得一说的是,您可以通过从左到右查看O(n)时间中的序列。 - 后缀中的下一个元素是枢轴点。 在我们的示例中,该值为2。枢轴点将始终小于后缀的第一个元素。 这意味着在后缀中肯定会有一个超出枢轴点的元素,并且如果我们将枢轴点从超过后缀的枢轴点支持元素更改为最小的元素-我们将得到一个超出原始序列的序列-在我们的情况下将是(0,1,3,5 ,3,2,0)。
即 此操作的结果将是最小可能的升序前缀。
- 在最后一步,我们需要按升序对后缀进行排序。 即 我们得到了最小的后缀。 在我们的示例中,它将是(0,2,3,5),整个序列看起来像(0,1,3,0,2,3,5)。
该值将是
下一个字典顺序重排。
至于该算法的实际应用,在我工作的所有时间中,我从不需要它,但是在接受Uber采访时,他们认为不是:))
为简单起见,所有代码都将用Go编写,我认为任何人都可以轻松将其翻译为任何其他编程语言。非常感谢PYXRU和646f67,让我大吃一惊 ,对算法进行了可能的优化-只需执行反后缀即可计算线性复杂度的置换。
func NextPermutationAlgorithm(w string) string { l := len(w) b := []byte(w) r := "no answer" for i:=l-1; i>0 ; i--{ if b[i-1] < b[i] { pivot := i for j := pivot; j < l; j++ { if b[j] <= b[pivot] && b[i-1] < b[j] { pivot = j } } b[i-1], b[pivot] = b[pivot], b[i-1] for j := l-1; i < j; i, j = i+1, j-1 { b[i], b[j] = b[j], b[i] } r = string(b) break } } return r }