【问题标题】:Algorithm for finding all permutations of a number [closed]查找数字的所有排列的算法[关闭]
【发布时间】:2014-11-09 21:42:26
【问题描述】:

我必须编写一个程序来给出一个数字的所有排列。例如,用户输入数字 4。我必须返回数字 1、2、3、4 的所有可能组合。我对获取所有排列的好方法有疑问。我有它,所以我的程序将数字 1-n 放入一个数组中。但是,我想不出一种获得排列的好方法。我知道我需要使用递归,但我的问题是首先获得排列的方法。我知道切换数字可能是最好的方法,但最好的方法是什么?

【问题讨论】:

标签: java algorithm int permutation


【解决方案1】:

理解算法的最简单方法是这样。要获得 1 到 4 的所有排列,您需要

  • 1,后跟2,3,4的排列
  • 2,后跟1,3,4的排列
  • 3,后跟1,2,4的排列
  • 4,后跟1,2,3的排列

这是一个相当标准的递归位。对于每个数字,递归地找到其他数字的所有排列,并将这个数字添加到开头。

【讨论】:

  • 这对于更大的数字(例如 6 或 7)如何工作?在那之前我不会还有找到所有数字排列的问题吗?
  • @ColinNull 它的工作方式相同——递归负责查找其他数字的所有排列。
  • @ColinNull:需要注意的是,在上面列出的 4 个案例中,您仍然需要置换的项目列表更小——只有 3 个项目而不是原来的 4. 那么如何生成它们中的每一个呢?只需使用这些较小的集合中的每一个调用您自己的生成所有排列函数,相信它会产生正确的答案!您真正需要解决“困难方式”的唯一情况是要置换的集合的长度为 1 - 然后答案很简单:)
  • @j_random_hacker 那么像 permuteAll 这样的方法将如何工作?我看到了递归的意义,但我仍然对如何让 permute all 方法起作用感到困惑?
  • @ColinNull 我可以建议您先编写一个更简单的递归方法来获得这个想法吗?编写一个方法fact(n) 来计算n 阶乘。如果 n 为 0,则返回 1;否则,返回 n*fact(n-1)。
【解决方案2】:

我们可以简单地使用recursion 通过递归选择一个元素然后将递归应用于该数组的子集来获得可能性。这是数字 1 到 3 的示例

【讨论】:

  • 当 TO 专门要求算法时,为什么要提供代码?
  • 我明白为什么这对 3 非常有效,但是,它如何适用于更大的数字,例如 6 或 7?我还没有学习递归,所以如果我的问题看起来很愚蠢,我深表歉意。
  • 为了更好地理解递归,请从简单的示例开始,例如查找数字 n 的阶乘
【解决方案3】:

递归是你的朋友。如果你有一个元素,你的解决方案显然是 [[1]]。对于两个元素,您可以采用所有“一个”解决方案(嗯,只有一个)并将 2 粘贴在 1 之前或之后,因此您得到 [[2,1], [1,2]]。对于三个元素,请采用所有“两个”解决方案并将三个放在第一、第二或第三位置。从 [2,1] 你得到 [3,2,1]、[2,3,1] 和 [2,1,3]。从 [1,2] 你得到 [3,1,2]、[1,3,2] 和 [1,2,3]。总之,您的解决方案是 [[3,2,1], [2,3,1], [2,1,3], [3,1,2], [1,3,2], [1, 2,3]].

【讨论】:

    【解决方案4】:

    注意chiastic-security's algorithm 生成 n 个数字的所有排列如何依赖于能够生成 n-1 个数字的所有排列?要使用他的算法,我们只需要这种能力,还有一件事:一种方法来生成仅包含一个数字的集合的所有排列。

    生成单个数字的所有排列是微不足道的:只有一个,仅由该数字本身组成。

    另外一个要求——生成 n-1 个数字的所有排列的能力呢?这似乎更难,但事实证明并非如此。假设我们要解决的问题 n=2:那么 n-1 = 1,然后我们就可以了,因为我们知道如何生成 1 个数字的所有排列。因此,在这里应用 chiastic-security 算法为我们提供了一种生成 2 个数字的所有排列的方法。如果我们想要解决的问题是 n=3,那么 n-1 = 2,并且我们刚刚确定我们可以生成 2 个数字的所有排列,所以我们仍然可以——我们知道如何生成所有3个数的排列。如果改为 n=4,则 n-3 = 3,并且我们刚刚确定可以生成 3 个数字的所有排列,因此我们也可以生成 4 个数字的所有排列。显然,这种推理可以永远持续下去——因此您可以通过这种方式生成任意数量的数字的所有排列。

    这种推理是非正式的,但可以使用mathematical induction 使其完全准确。如果可以应用归纳法,那么令人惊讶的结果是,我们永远不必用“艰难的方式”解决任何“大”问题——我们总是可以将它们分解为一个或多个小问题,而这些小问题又可以分解为较小的问题,直到达到一个或多个易于解决的“基本案例”——然后可以将较大问题的解决方案从这些解决方案拼凑成更简单的子问题。

    【讨论】:

    • 是的,他的推理很好,我知道它减少了 n 1,从而降低了复杂性。但是,对于像 8 这样的数字,使用他的逻辑我只需要进行 7 次排列,这仍然需要找到 5040 个排列,并将正确的数字添加到每个排列的开头。我不知道我是否只是把它复杂化了,但我想不出一种方法来获得每一个可能的排列。我找不到允许每种组合的数字切换特定模式。
    • @ColinNull:假设你的函数名为perm()。当 perm({1,2,3,4,5,6,7,8}) 被调用并且需要生成 7 元素集合 {2, 3, 4, 5, 6, 7, 8} 的所有 5040 个排列时,它怎么做呢?致电perm({2, 3, 4, 5, 6, 7, 8})。就这么简单!
    • @ColinNull:这递归:调用“你自己”来解决较小的子问题。
    • @ColinNull:我假设您在此示例中遇到的困难是如何生成 {2,3,4,5,6,7,8} 的所有 5040 个排列的集合。一旦你有了这些排列,你就可以创建所有 5040 个 {1,2,3,4,5,6,7,8} 以 1 开头的排列,方法是在每个排列前面放一个 1。您需要对 8 位数字中的每一位重复该过程;之后,您将生成所有以 1 开头的排列,所有以 2 开头的排列,...,直到 8 —— 这就是所有排列。
    • 所以我的方法基本上将一个数字“分解”成我可以合理地从中获得排列的东西,然后添加第一个数字,依此类推。我可以不断地调用这个方法,直到我拥有所有可能的组合。这就是递归,一遍又一遍地使用相同的方法来解决问题。将其分解为更小更简单的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多