该算法如何生成下一个按字典顺序排列的排列有效?

时间:2013-07-19 12:16:30

标签: algorithm permutation lexicographic

这是我发现的用于订购词典排列的一步一步的过程:

  1. 取出先前打印的排列,找到最右边的字符,该字符小于下一个字符。我们将这个角色称为“第一个角色”。

  2. 现在找到“第一个字符”的上限。天花板是“第一个字符”右边的最小字符,大于“第一个字符”。让我们将ceil字符称为“第二个字符”。

  3. 交换上面两步中找到的两个字符。

  4. 在“第一个字符”的原始索引之后对子字符串(以非递减顺序)排序。

  5. 来源:http://www.geeksforgeeks.org/lexicographic-permutations-of-string/

    我已经为它编写了我的伪代码,我现在也要开始编程。我理解算法中发生了什么,但我不确定它为什么会起作用。与第2步一样,为什么天花板字符必须是“'第一个字符'右边的最小字符,大于'第一个字符'”。我明白,如果你不这样做,它就行不通,但我不明白你为什么这样做。

    如果有人可以向我解释为什么你需要算法中的每一步都很棒,这会让我在启动代码时更加舒服。

    编辑:我应该提到我理解你为什么要将子字符串重新排列为按顺序排列,以便找到最小的置换,我不明白的是第1步和第2步关于为什么要交换天花板和第一个字符

3 个答案:

答案 0 :(得分:3)

基本上我们想要从最右边以尽可能小的数量增加我们可以的第一个​​字符,并使用其右边的字符进行尽可能小的排列(我们将如何做到这一点)。为什么我们想要做的是,我希望,这非常符合逻辑。如果不是,可能有助于考虑数字的排列(制作一个数字) - 你可以继续在数字中加一,直到你得到另一个数字的排列,虽然这是一种更有效的方法将神奇地找到我们需要增加的最左边数字和增加它的数量,并简单地得到右边数字的最小排列,这正是这个算法所做的。

嗯,我们不能只将角色增加到任何其他角色,它必须是一个已经存在于排列中的角色。如果这个角色存在于左侧,那将不会真正有所帮助,因为它还需要改变左侧的角色,这将使我们最终得到更大的排列。所以我们需要在右边使用一个字符,除此之外,它必须是比这个字符更大的最小字符。

所以,从右边开始,对于每个角色A,看起来对于大于A的最小角色(称为B)。如果您找不到,请尝试下一个字符。上面的段落解释了我们想要将A增加到B的值。一旦我们完成了这个,我们现在剩下2个B来解决这个问题,我们将B减少到A的值(这基本上只是交换A和B)。从这里我们将所有东西都安排在A所在的位置。由于我们要进行此修复,因此新的A现在可能不在应有的位置并不重要。

我们如何修复剩余的角色?好吧,我们想要它们的最小排列,这就是那些有序的字符。

这将照顾步骤2-4。

第1步怎么样?这实际上只是算法的优化。如果我们从右边开始并找到右边存在较大字符的第一个字符,那么我们需要找到比第一个字符小的第一个字符是不合理的。它右边的字符,或者更确切地说,字符位于右边的一个位置?想想987654321 - 我们无法在此处执行任何操作,因为所有字符都比右边的字符大。

用一个例子来解释:

选择ABDC

右边存在较大字符的第一个字符是B。大于B最小字符为C

因此,下一个可能的排列将如下所示:AC???未知)

其余两个字符为DB,我们需要找到最小的排列,即BD。所以我们把它放在一起:ACBD

在交换BC方面 - 我们需要B成为C(来自第2段),但仍需要B在字符串中,它是一个有效的排列(所以我们不能用B替换C)并且在B结束的地方并不重要,因为之后,我们发现其余字符的最小排列。

答案 1 :(得分:1)

该算法的主要思想是如何找到给定排列的下一个排列。 根据您编写的链接,可以通过在最后打印的排列中找到小于其正确字符的最右侧字符来完成。

证明:

表示P = P [1] p [2] p [3] .. p [n]作为最后打印的排列。 假设k是最右边的字符的索引,例如P [k]> P [K + 1]。

根据Next的定义,So Next(P)= P [1] p [2] p [3] .. p [k + 1] p [k] p [k + 2] p [k + 3] .. p [N]。

假设有P'这样的值(P)<值(P')<值(下一个(P))。

将k'表示为最小指数,如P [k']!= P'[k']。

有3种选择:

  • k'< k:在那种情况下,因为值(P')>值(P),我们得到P'[k']> P [K']。但是直到k'指数,Next(P)和P是相同的,所以P'[k']>接下来(P)[k']并且直到k'它们相同(因为k'

  • k'&gt; k:P'[k']&gt; P [k']因为值(P')>值(P),但我们知道,直到k'P和P'相同,所以有k''&gt; k'使得P [k''] < P [k']与Next的定义相反(k是最右边P [k]

  • k'= k':如果Next(P)[k']&lt; P'[k]我们将得到该值(P')&gt;值(Next(P))不是真的。如果P'[k] = Next(P)[k],因为k是最右边的并且因为值(P')&lt; = value(Next(P))我们得到P'= Next(P)哪个可以' t为真,因为值(Next(P))&gt;值(P')。并且如果P'[k] <接下来(P [k])它不能与选项2类似。

所以我们得到这样的P'是不可能的=&gt;接下来(P)是我们想要的P的下一个排列。

实施例: P =“DFEBCA” 下一步(P)=“DFECBA”。

因此k = 4,因为4是最右边的索引,例如P [i]&lt; P [I + 1]。

如果你试图找到其他排列P',那么值(P)<值(P')&lt;值(下一个(P)) 你找不到。

答案 2 :(得分:0)

要打印单词的下一个词典术语,我们需要遵循以下所述的算法: - &gt;

  1. 计算单词的长度,使指针指向单词的最后一个和倒数第二个字符。如果倒数第二个字符小于最后一个字符,则交换两个字符。这是必要的答案。
  2. 如果第1个案例没有出现,那么让你的第二个最后一个指针(比方说i)减1,然后搜索比位于右边的子串中位置最小的字符大的字符。如果找到这样的字符,则用位置字符与找到的天花板字符交换(一个在右边找到)。
  3. 现在,最后对指针右侧的子串进行排序,否则重复第二步。